Compare commits

..

2387 Commits

Author SHA1 Message Date
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
Alan Evans a8e4e8e882 Bump version to 4.70.0 2020-08-26 17:25:54 -03:00
Alan Evans cf93760d00 Updated language translations. 2020-08-26 17:25:54 -03:00
Greyson Parrelli dd8b9ff8fb Add support for article dates in link previews. 2020-08-26 17:25:54 -03:00
Alan Evans bfed03b7b5 Manage group links behind feature flag. 2020-08-26 17:25:54 -03:00
Alan Evans 860f06ec9e Join group via invite link. 2020-08-26 12:51:25 -03:00
Alex Hart b58376920f Order pinned conversations in "first added" order instead of reordering as messages come in. 2020-08-26 11:13:01 -03:00
Alan Evans 4ace075ddf Display membership count in link preview description field. 2020-08-26 09:26:25 -03:00
Fumiaki Yoshimatsu dda98a474d Listen to the uiMode configuration changes.
Fixes #9736
Fixes #9922
2020-08-25 17:11:29 -03:00
Alan Evans f1c0df7d87 Update KBS Service Id on staging. 2020-08-25 17:10:07 -03:00
Greyson Parrelli c78e098cb4 Add support for link preview descriptions. 2020-08-25 16:05:39 -04:00
Alex Hart a3438c4f8d Change where edit profile screen requests camera permission. 2020-08-25 16:35:16 -03:00
Alan Evans 92ecf2d5de Add group link join version feature flag. 2020-08-25 16:35:06 -03:00
Alex Hart f18b653725 Fix crash when scrolling to the top of a conversation. 2020-08-25 15:17:21 -03:00
Alex Hart 5128438cfb Fix action bar usability in vertical screen split. 2020-08-25 09:33:11 -03:00
Greyson Parrelli f29f25822b Have DatabaseFactory.getMmsDatabase() return MessageDatabase. 2020-08-24 16:40:47 -04:00
Greyson Parrelli ecfe218840 Bump version to 4.69.6 2020-08-24 14:34:53 -04:00
Greyson Parrelli dd33d2b5d0 Updated language translations. 2020-08-24 14:34:28 -04:00
Alex Hart 12a8d4e10b Fix crash on multi-archive. 2020-08-24 14:34:28 -04:00
Alex Hart c5c2fb31b1 Fix CREATE statement for RecipientDatabase. 2020-08-24 14:25:37 -04:00
Alex Hart 343b7faf98 Bumped version to 4.69.5 2020-08-24 11:16:41 -03:00
Alex Hart 18aa8bbf60 Updated language translations. 2020-08-24 11:16:41 -03:00
Greyson Parrelli a358d1630f Rotate the CDS feature flag. 2020-08-24 11:16:41 -03:00
Alan Evans 01375b321c Don't release bitmaps managed by Glide, and don't cache group preview avatars. 2020-08-24 11:16:41 -03:00
Alex Hart d2739d52e0 Remember position in react-with-any-emoji picker. 2020-08-24 11:16:41 -03:00
Alex Hart 4668510106 Fix crash when archiving multiple conversations. 2020-08-24 11:16:41 -03:00
Alex Hart ffcd311c90 Fix strange long press behavior in convo list.
Fixes #9944
2020-08-24 11:16:41 -03:00
Alex Hart b94a636542 Apply Content-Range and Content-Length headers to resumable upload request. 2020-08-24 11:16:41 -03:00
Jim Gustafson a7aec6bfbc Update to RingRTC v2.5.0 2020-08-24 11:16:41 -03:00
Greyson Parrelli 190ca9eddd Have DatabaseFactory.getSmsDatabase() return MessageDatabase.
Slowly moving towards a single interface.
2020-08-24 11:16:41 -03:00
Greyson Parrelli 2cf9eb69eb Add support for handling unknown protobuf fields. 2020-08-24 11:16:41 -03:00
Alan Evans ffcb90da52 Accept any length group link password. 2020-08-24 11:16:41 -03:00
Alan Evans 878b0c9275 Change group invite link host. 2020-08-24 11:16:41 -03:00
Evan Hahn 5505cb0dea Update donation link in contribution instructions. 2020-08-24 11:16:41 -03:00
Alex Hart 7ac14dccda Refresh username in onResume and utilize imeAction. 2020-08-24 11:16:41 -03:00
Greyson Parrelli 6cffd0a723 Update link preview sync settings.
We need to rotate the link preview setting to avoid newer desktops with
older mobile clients from generating proxy-less previews.
2020-08-24 11:16:41 -03:00
Alan Evans 220ebf93c7 During registration, persist time that call me is available.
Fixes #9926
2020-08-19 16:32:01 -04:00
Greyson Parrelli d0681a5592 Make calling status strings consistent.
Fixes #9904
2020-08-19 16:32:01 -04:00
Alan Evans 09d167c16d Group link preview and info display bottom sheet. 2020-08-19 16:32:01 -04:00
Alan Evans 477bb45df7 Group invite link epoch support. 2020-08-19 16:32:01 -04:00
Alex Hart e006306036 Utilize ItemCallback for ReactWithAnyAdapter.
Fixes #9918
2020-08-19 16:32:01 -04:00
Greyson Parrelli 065cbcf0f9 Bump version to 4.69.4 2020-08-19 16:08:07 -04:00
Greyson Parrelli 7a6b958bbe Updated language translations. 2020-08-19 16:07:46 -04:00
Cody Henthorne ef6a5b6599 Fix bug causing call requests to not be handled properly. 2020-08-19 15:49:16 -04:00
Greyson Parrelli cdae919b5e Bump version to 4.69.3 2020-08-19 10:03:26 -04:00
Greyson Parrelli 12889f4549 Updated language translations. 2020-08-19 10:03:04 -04:00
Greyson Parrelli 089d59b691 Properly mark local note-to-self attachments as uploaded. 2020-08-19 09:59:37 -04:00
Alex Hart b3e247e9cc Fix crash when loading vector from typed array.
Fixes #9933
2020-08-19 10:45:01 -03:00
Greyson Parrelli 56392b87f7 Bump version to 4.69.2 2020-08-18 19:22:42 -04:00
Greyson Parrelli 1b1a4aeb38 Updated language translations. 2020-08-18 19:22:18 -04:00
Greyson Parrelli 16147e0c08 Ensure link preview fetches are canceled on message send. 2020-08-18 18:34:18 -04:00
Cody Henthorne 139317cf1b Improve various aspects of mentions. 2020-08-18 18:13:45 -04:00
Cody Henthorne 72b94127fb Stop muted threads from triggering full notification updates. 2020-08-18 14:15:55 -04:00
Alan Evans 1f1fc94d22 Fix flakey robolectric test. 2020-08-18 11:57:35 -03:00
Greyson Parrelli a574fe026c Bump version to 4.69.1 2020-08-17 12:04:41 -04:00
Greyson Parrelli aa82083d30 Updated language translations. 2020-08-17 12:04:41 -04:00
Greyson Parrelli 08d5df70c2 Don't show the link preview megaphone if previously disabled. 2020-08-17 12:04:41 -04:00
Greyson Parrelli 29b8fa5897 Keep pinned chats at the top of the 'recent' chat section. 2020-08-17 11:12:10 -04:00
Alex Hart e96faf31d4 Fix browser opening on long-press of debug log links. 2020-08-17 11:54:41 -03:00
Greyson Parrelli 157a73aa99 Fix title of conversation pin menu item. 2020-08-17 10:37:17 -04:00
Greyson Parrelli bdd298c8a0 Prevent swipe actions on the 'Pinned' header. 2020-08-17 10:31:28 -04:00
Greyson Parrelli 3f7dd21186 Do not attempt to create link previews for .onion links. 2020-08-17 10:27:30 -04:00
Greyson Parrelli 086b708cf7 Fix NPE when double-tapping the conversation pinning icon. 2020-08-17 10:07:58 -04:00
Alan Evans 57e0e57f48 Fix NPE when link preview image cannot be decoded. 2020-08-15 10:10:15 -03:00
Greyson Parrelli 4b7efbfdc0 Bump version to 4.69.0 2020-08-14 15:54:06 -04:00
Greyson Parrelli 7dc2653042 Updated language translations. 2020-08-14 15:54:06 -04:00
Cody Henthorne e428453835 Fix conversation list bug with pinned chats.
Co-authored-by: Alex Hart <alex@signal.org>
2020-08-14 15:54:06 -04:00
Greyson Parrelli f84c8229de Revert "Replace a call to a deprecated method to update context with the new one."
This reverts commit 5f0d384c9e.

Introduced a bug where the system theme wasn't changing until app
restart.
2020-08-14 15:54:06 -04:00
Alex Hart a73427d68d Fix issues with conversation list position. 2020-08-14 15:54:05 -04:00
Alan Evans e4456bb236 Handle GV2 addresses. 2020-08-14 15:54:05 -04:00
Alex Hart 06eadd0c15 Add mentions unread counter. 2020-08-14 15:54:05 -04:00
Alan Evans 3c90dfa660 Ensure a GV2 update message mentioning you as a new member is first in the list. 2020-08-14 15:54:05 -04:00
Greyson Parrelli ace1b8ee71 Update link preview settings and add some UI polish. 2020-08-14 15:54:05 -04:00
Cody Henthorne 676356e800 Add Mentions Megaphone. 2020-08-14 15:54:05 -04:00
Greyson Parrelli f732e54c22 Update group size flag. 2020-08-14 15:54:05 -04:00
Cody Henthorne cdc2e74f68 Stop conversations without meaningful messages from showing in list. 2020-08-14 15:54:05 -04:00
Cody Henthorne 724f3e872b Update Mention UI/UX to match latest designs. 2020-08-14 15:54:05 -04:00
Alex Hart d63e5165eb Add ability to pin up to 4 conversations. 2020-08-14 15:54:05 -04:00
Cody Henthorne 9892c4392e Fix janky avatar preview transition for notched devices. 2020-08-14 15:54:05 -04:00
Cody Henthorne 5ced1a775c Fix bug where SN change dialog appeared unnecessarily. 2020-08-14 15:54:05 -04:00
Cody Henthorne 761de1318e Update mention data during recipient merge. 2020-08-14 15:54:05 -04:00
Cody Henthorne 02508512d5 Fix incorrect snippet generation by ignoring profile name change messages. 2020-08-14 15:54:05 -04:00
Greyson Parrelli 6e6105af05 Open up link previews to work with all sites. 2020-08-14 15:54:05 -04:00
Jared Andrews d569419e13 Fixes conversation overflow menu items not being tappable.
Fixes #9908
2020-08-13 19:47:46 -04:00
Greyson Parrelli 93f1641803 Bump version to 4.68.8 2020-08-10 21:13:19 -04:00
Greyson Parrelli ff52bf93fa Make the CDS flag remote capable. 2020-08-10 13:27:11 -04:00
Greyson Parrelli a039275a0c Bump version to 4.68.7 2020-08-10 11:40:37 -04:00
Greyson Parrelli a98d10104d Updated language translations. 2020-08-10 11:39:30 -04:00
Alan Evans 8924bc59b1 Hide legacy group warning when GV2 create feature flag is off or MMS is forced.
Fixes #9913
2020-08-08 17:43:07 -03:00
Greyson Parrelli eefe60a9c9 Bump version to 4.68.6 2020-08-07 19:37:05 -04:00
Greyson Parrelli fe1cb3d904 Updated language translations. 2020-08-07 19:36:26 -04:00
Greyson Parrelli 0448278a78 Include a recipient in sent transcripts when possible. 2020-08-07 19:20:35 -04:00
Greyson Parrelli 99c0c2ff4c Fix crash when opening debuglogs during registration. 2020-08-07 19:20:35 -04:00
Greyson Parrelli b369b734ca Improve storage service insert recovery. 2020-08-07 19:20:35 -04:00
Greyson Parrelli 57150a20fd Make verificationV2 a separate flag. 2020-08-07 19:20:35 -04:00
Cody Henthorne 1634d7d531 Show mention picker immediately after @ entered. 2020-08-07 15:27:15 -04:00
Cody Henthorne d563de4207 Add mention detection to search flows. 2020-08-07 15:18:40 -04:00
Greyson Parrelli 5cd4b82ed0 Bump version to 4.68.5 2020-08-06 21:03:31 -04:00
Greyson Parrelli 5f728d348c Updated language translations. 2020-08-06 21:02:22 -04:00
Greyson Parrelli 596c4b6e40 Don't include inactive groups when listing groups in common. 2020-08-06 20:57:50 -04:00
Alex Hart 36d1e7c44a Disable Contact Join Notification via Action. 2020-08-06 20:57:50 -04:00
Alan Evans 25c17082f2 Share a common groups v2 capacity flag across clients. 2020-08-06 20:57:50 -04:00
Alan Evans 810ccf8e94 Improve GV2 Invitation revoke experience. 2020-08-06 20:57:50 -04:00
Alex Hart c8ed0b19f0 Do not update thread on profile name change. 2020-08-06 20:57:50 -04:00
Alan Evans 9e09444c65 Increment the Groups V2 feature flags version. 2020-08-06 20:57:50 -04:00
Greyson Parrelli 5923fa0cd5 Block sends on CDS lookups. 2020-08-06 20:57:50 -04:00
Cody Henthorne b2d4c5d14b Add mentions for v2 group chats. 2020-08-06 20:57:50 -04:00
Alex Hart 0bb9c1d650 Add light and dark spinner lotties with correct coloring. 2020-08-06 20:57:50 -04:00
Alan Evans fbfa3abffd Skip delete actions where the removed member/pending member is not in the group. 2020-08-06 20:57:50 -04:00
Alan Evans b5656aa5dd Exclude non-translatable multiline blocks. 2020-08-06 20:57:50 -04:00
Alan Evans d53fd6a109 Change invite cancel to invite revoke. 2020-08-06 20:57:50 -04:00
Alan Evans b0650b926b Fix pending member group edit rights. 2020-08-06 20:57:50 -04:00
Alan Evans 845f6a0a93 Notify user during group create of members that do not support GV2. 2020-08-06 20:57:50 -04:00
Alex Hart d8daa83c79 Remove autoLink from conversation update items. 2020-08-06 20:57:50 -04:00
Alex Hart 7bb0199e83 Change additional groups copy to match iOS. 2020-08-06 20:57:50 -04:00
Alex Hart f014dadf06 Adjust Zoom levels and transition duration. 2020-08-06 20:57:50 -04:00
Alex Hart 393e54ce91 Update how we mark messages as read. 2020-08-06 20:57:50 -04:00
Alan Evans fdf4ad9543 Remove the GV2 "anyone" access level. 2020-08-06 20:57:50 -04:00
Fumiaki Yoshimatsu 5f0d384c9e Replace a call to a deprecated method to update context with the new one.
Fixes #9736
2020-08-06 20:57:50 -04:00
Christian Ascheberg 4271700046 Do not collapse list to hide only one entry. 2020-08-06 20:57:50 -04:00
Niko Lockenvitz e153b0ab78 Fix message compose hint on fullscreen.
Fixes #5294
Closes #5348
2020-08-06 20:57:50 -04:00
Alan Evans 26868ae668 Get authoritative profile keys from group changes only. 2020-08-06 20:57:50 -04:00
Greyson Parrelli 17c0364eda Ensure group avatars have V2 attachmentIds. 2020-08-06 20:57:50 -04:00
Alan Evans b28ac7af8c Additional tests around rigid Groups V2 change application. 2020-08-06 20:57:50 -04:00
Greyson Parrelli 2dcaa21a44 Remove UuidRecipientError. 2020-08-04 19:12:25 -04:00
Greyson Parrelli 33cc8363f9 Add internal setting to see recipient details. 2020-08-04 19:12:25 -04:00
Greyson Parrelli 9b61e1c85c Show a message request for certain GV2 adds. 2020-08-04 19:12:25 -04:00
Greyson Parrelli 6f53fdc02d Clean up log statement in FcmFetchService. 2020-08-04 19:12:25 -04:00
Greyson Parrelli 6f850f5a55 Bump version to 4.68.4 2020-08-04 17:53:22 -04:00
Greyson Parrelli a482a4b1f4 Updated language translations. 2020-08-04 17:46:11 -04:00
Greyson Parrelli 3664e6f96d Fix processing of unsupported messages. 2020-08-04 17:37:25 -04:00
Greyson Parrelli dda8808173 Bump version to 4.68.3 2020-08-03 12:30:51 -04:00
Greyson Parrelli 63a24c23cc Updated language translations. 2020-08-03 12:29:52 -04:00
Greyson Parrelli 1ec3a72f79 Fix issue with thread summaries being updated after message deletion.
Fixes #9902
2020-08-03 10:36:02 -04:00
Greyson Parrelli 566285ec0e Fix crash in MMS group creation.
Fixes #9901
2020-08-03 10:03:45 -04:00
Greyson Parrelli d5ba82338d Fix issue with text rendering in search results. 2020-08-03 09:47:27 -04:00
Greyson Parrelli cbecd2a2fc Bump version to 4.68.2 2020-07-31 16:47:55 -04:00
Greyson Parrelli 3772dd40ac Updated language translations. 2020-07-31 16:46:01 -04:00
Alex Hart f69a0f0261 Refine reaction details fragment. 2020-07-31 16:49:52 -03:00
Alex Hart cb323ffb84 Fix reaction overlay toolbar and status bar. 2020-07-31 15:51:41 -03:00
Alex Hart 0db73e71a0 Remove sticky header on list reinitailization.
When we forward a message or share into the app, it is possible that we are going to reuse the same activity. In this case, when the adapter was reinitialized, we were just adding a new ItemDecoration every time.

This fix checks if we've already added one and removes it if necessary, just like the last seen decorator.
2020-07-31 14:26:31 -03:00
Alex Hart eeb0c838db Fix masking when attachment keyboard is visible. 2020-07-31 11:34:46 -03:00
Greyson Parrelli dc48ee5aed Bump version to 4.68.1 2020-07-30 23:32:20 -04:00
Greyson Parrelli c0acfa57a9 Updated language translations. 2020-07-30 23:32:19 -04:00
Greyson Parrelli 3e166ef927 Fix issue where group updates were mis-rendered. 2020-07-30 23:32:19 -04:00
Greyson Parrelli 4942d83de5 Properly render reset session update messages. 2020-07-30 23:32:19 -04:00
Alex Hart 4c30b39e71 Add section to recent reactions page listing emoji already applied to message. 2020-07-30 23:32:19 -04:00
Alex Hart e55f4fe6b6 Save preference on emoji send. 2020-07-30 22:26:59 -04:00
Greyson Parrelli aff74cffa0 Fix crash with UnknownSenderView.
The listener was being called on a background thread, but it was doing
UI work.
2020-07-30 13:31:51 -04:00
Alex Hart 8b29bb8664 Fix info icon in light mode. 2020-07-30 10:48:45 -03:00
Greyson Parrelli 3cee57b6c2 Bump version to 4.68.0 2020-07-29 23:54:46 -04:00
Greyson Parrelli 857f4a4fc8 Updated language translations. 2020-07-29 23:54:09 -04:00
Jim Gustafson a942293a74 RingRTC v2.4.0 Release Integration.
Co-authored-by: Peter Thatcher <peter@signal.org>
2020-07-29 23:43:06 -04:00
Greyson Parrelli 550b121990 Prevent UUID-only contacts from being added to GV1 groups. 2020-07-29 23:43:06 -04:00
Alex Hart cc84901a49 Add dropshadow to emoji variation popup. 2020-07-29 23:43:06 -04:00
Alex Hart 9d3764c5d9 Reactions UX polish. 2020-07-29 23:43:06 -04:00
Greyson Parrelli 0950235ccd Fix typo in RemappedRecords. 2020-07-29 23:19:21 -04:00
Greyson Parrelli 8ed7fc894e Improve handling of partially bi-directional text. 2020-07-29 23:19:21 -04:00
Greyson Parrelli e504ffa225 Clean up conversation list data loading sequence.
- The Paging library was giving us empty paged lists when loading was
invalidated, but only *sometimes*. This library, man. Fixed it by
ignoring invalid lists, which you'd think the library would do for us...
- Noticed we were doing a ton of list refreshes because of how we were
listening to archive count. Switched from combine to switchMap.
- Noticed that we could become double-subscribed to LiveDatas in the
ConversationListFragment if you went to archived. Fixed by observing on
the fragment's view lifecycle.

Fixes #9803
2020-07-29 23:19:21 -04:00
Cody Henthorne 9c63b37bb4 Refactor use of MessageRecord to increase flexibility of ConversationAdapter. 2020-07-29 23:19:21 -04:00
Greyson Parrelli 5c110ca359 Remove UUIDs from GV1 membership lists. 2020-07-29 23:19:21 -04:00
Cody Henthorne 1ab61beeb9 Add initial Mentions UI/UX for picker and compose edit. 2020-07-28 15:20:20 -04:00
Alan Evans 8e45a546c9 Fix NPE on Group multi-invite. 2020-07-28 15:20:20 -04:00
Alan Evans 745a7f76ea Change position of GroupsV2 leave update message. 2020-07-28 15:20:20 -04:00
Alan Evans 8cb9ab3204 Fetch newly found profiles on Groups V2 inline. 2020-07-28 15:20:20 -04:00
Alan Evans 12533d1414 Ensure profile key is up to date on Group V2 conversation open. 2020-07-28 15:20:20 -04:00
Alan Evans bd1c164d57 Live group update messages on conversation list and conversation. 2020-07-28 15:20:20 -04:00
Greyson Parrelli 7446c2096d Don't ellipsize multi-line text in conversation list.
Instead, basically convert newlines to spaces.
2020-07-28 15:19:52 -04:00
Greyson Parrelli 8ce5c4b885 Cleanup naming of RecipientDatabase GLOB search. 2020-07-28 15:19:52 -04:00
Alan Evans ab76112f5f Prevent leading and trailing whitespace in group names. 2020-07-28 15:19:52 -04:00
Alan Evans 9c54e39eae Adjust scope of Groups V2 feature flag. 2020-07-28 15:19:52 -04:00
Greyson Parrelli 61eab44474 Bump version to 4.67.3 2020-07-27 18:04:05 -04:00
Greyson Parrelli f6285ec710 Updated language translations. 2020-07-27 18:02:31 -04:00
Alex Hart ed878ec4b4 Add more generic SMS verification code pattern. 2020-07-27 17:57:56 -04:00
Greyson Parrelli e38d41d67a Reduce the number of cats in giphy sticker search results. 2020-07-27 15:25:26 -04:00
Greyson Parrelli 3d237d72bd Fix issue where feature flag fetches weren't limited. 2020-07-27 15:25:01 -04:00
Cody Henthorne 8044d2390c Fix bug causing profile updates to unarchive threads. 2020-07-27 13:32:38 -04:00
Greyson Parrelli 6b82e6b5ac Bump version to 4.67.2 2020-07-24 14:31:06 -04:00
Greyson Parrelli 842e6a93e2 Updated language translations. 2020-07-24 14:31:06 -04:00
Alan Evans f140f054e5 Ignore typing indicators from blocked group members. 2020-07-24 14:31:06 -04:00
Greyson Parrelli 5cd4726e23 Do not show profile name changes if names are visually identical.
Fixes #9860
2020-07-24 14:30:58 -04:00
Greyson Parrelli bccc58d693 Bump version to 4.67.1 2020-07-22 22:58:21 -04:00
Greyson Parrelli e25f1c1481 Updated language translations. 2020-07-22 22:58:21 -04:00
Greyson Parrelli fc4e690996 Revert "Ensure GV1 length is exactly the length expected."
This reverts commit 8e962bf992.
2020-07-22 22:58:21 -04:00
Greyson Parrelli dadb2f9d37 Allow auto-downloads from groups you've accepted. 2020-07-22 22:58:21 -04:00
Greyson Parrelli 5bf15b0587 Fix casing issues with non-ASCII characters in contact search.
SQLite's case-related stuff is ASCII-only. That means that even though LIKE is supposed to be case-insensitive, it fails when used on non-ASCII characters.

There appears to be no relief in SQLite itself, so I swapped our contact search to use GLOB instead of LIKE and wrote a little thing to convert query strings into a case-insensitive unicode-compatible patterns. Didn't see any noticeable performance difference.
2020-07-22 22:58:21 -04:00
Cody Henthorne 5f9c0c3204 Fix bug with skipping resend message on safety number change. 2020-07-22 22:58:21 -04:00
Alan Evans dfa4f0c309 Fix group change failure reason display logic. 2020-07-22 22:58:21 -04:00
Greyson Parrelli f0063b4b0d Sync ContactRecords as whitelisted if they're a system contact. 2020-07-22 22:58:21 -04:00
Alan Evans 5dc51c34ea Fix recipient resolution during add to Groups V2. 2020-07-22 22:58:21 -04:00
Greyson Parrelli 5bf7a55bfa Bump version to 4.67.0 2020-07-21 16:11:45 -04:00
Greyson Parrelli eb9ae8d5dc Updated language translations. 2020-07-21 16:11:45 -04:00
Greyson Parrelli 2a133587cc Add a flag for recipientTrust. 2020-07-21 16:11:45 -04:00
Greyson Parrelli 0e4a19c368 Improve exception stack traces in OptimizedMessageNotifier. 2020-07-21 15:31:53 -04:00
Greyson Parrelli 813c820227 Fix issue with GV1 avatars using attachmentsV3. 2020-07-21 15:31:53 -04:00
Greyson Parrelli 870cee5707 Remove uuidOnlyContacts feature flag. 2020-07-21 15:31:53 -04:00
Alan Evans 4e55d2d941 Tint pending group invites menu icon. 2020-07-21 15:31:53 -04:00
Alan Evans 8e962bf992 Ensure GV1 length is exactly the length expected. 2020-07-21 15:31:53 -04:00
Cody Henthorne 0815715f7b Enable call requests always. 2020-07-21 15:31:53 -04:00
Alan Evans 85e4697b7f Increment the Groups V2 feature flags version. 2020-07-21 15:31:53 -04:00
Alan Evans 16fdb9bf4c Make identity record list immutable. 2020-07-21 12:53:25 -03:00
Greyson Parrelli 46f3d50a54 Increment the attachmentsV3 feature flag version. 2020-07-21 10:49:19 -04:00
Alan Evans 3a38240fb2 Groups V2 group manager copy updates. 2020-07-21 11:47:11 -03:00
Greyson Parrelli 662f0b8fb6 Improve detection of websocket drained status.
Will now work when you lose and regain network. Also removes the
unnecessary InitialMessageRetriever.
2020-07-21 10:38:42 -04:00
Alan Evans 96ce42ae91 Legacy group learn more badge and info bottom sheet. 2020-07-21 06:05:16 -03:00
Alan Evans 93f587b851 For atomic Groups V2 block and leave, block after leaving group. 2020-07-21 06:04:44 -03:00
Greyson Parrelli 89a940ec81 Fix issue with contact syncing with attachmentsV3. 2020-07-20 17:57:22 -04:00
Alan Evans a33771b15d Added progress feedback to leave and block group actions and additional group v2 error handling. 2020-07-20 15:20:56 -03:00
Greyson Parrelli 9a566e5559 Group together skin tone variations of the same reaction. 2020-07-20 10:26:39 -04:00
Greyson Parrelli 6e75d42a92 Enable skin tone selection for emoji reactions. 2020-07-20 10:26:39 -04:00
Alan Evans 575413cac9 Wait for message queue to drain before updating v2 groups. 2020-07-20 11:09:42 -03:00
Greyson Parrelli 6a9476c6d0 Fix retry issues with RotateProfileKeyJob. 2020-07-19 10:45:20 -04:00
Greyson Parrelli 5468f1705c Ensure we refresh attributes if key changes from storage service. 2020-07-19 10:45:20 -04:00
Greyson Parrelli 5ea132e712 Delay directory refresh until registration is complete. 2020-07-19 10:22:05 -04:00
Cody Henthorne 8128fcf8bc Hide compose for inactive groups. 2020-07-19 09:32:16 -04:00
Greyson Parrelli e89655f793 Resolve newly-entered numbers before starting a conversation. 2020-07-19 09:32:16 -04:00
Cody Henthorne 2db2b068c4 Do not show typing indicators for inactive groups. 2020-07-19 09:32:16 -04:00
Alan Evans a59e214317 Show Group V2 invited member dialog explaining invites on new group and add to group. 2020-07-19 09:32:16 -04:00
Cody Henthorne ae2b6e4d7a Prevent last admin from leaving without selecting new admin. 2020-07-19 09:32:16 -04:00
Alan Evans b10fc6a0b0 Support Groups v2 Change Epochs. 2020-07-19 09:32:16 -04:00
Cody Henthorne 70977e5228 Show expiration time exactly as set instead of rounding. 2020-07-19 09:32:16 -04:00
Greyson Parrelli 4482391574 Update libphonenumber to v8.12.6 2020-07-19 09:32:16 -04:00
Greyson Parrelli bd078fc883 Handle UUID-only recipients and merging. 2020-07-19 09:32:16 -04:00
Alan Evans 644af87782 Groups V2 invite decline. 2020-07-19 09:32:16 -04:00
Greyson Parrelli 1ce36c1069 Bump version to 4.66.8 2020-07-17 17:32:33 -04:00
Greyson Parrelli 0a71005ecc Updated language translations. 2020-07-17 17:32:07 -04:00
Cody Henthorne 698618a4b3 Only show profile updates in active groups. 2020-07-17 17:32:07 -04:00
Alan Evans f9642dd79f Reduce scrim overlap when scrolling new manage screens. 2020-07-17 17:32:07 -04:00
Cody Henthorne 85d1a3c016 Add system contact indicator to recipient bottom sheet. 2020-07-17 17:32:07 -04:00
Alan Evans 38c74c81a6 Add qa to translate task. 2020-07-17 17:32:07 -04:00
Greyson Parrelli 4c04991b70 Refresh recipient after viewing system contact details.
They might have changed the name or otherwise edited the contact, so we
want to try to keep things in sync.
2020-07-17 17:32:07 -04:00
Cody Henthorne 293a339fed Only show delete action when long pressing on profile change update. 2020-07-17 17:32:07 -04:00
Greyson Parrelli 5255a527f9 Do not show profile name changes for blocked users. 2020-07-17 17:32:07 -04:00
Cody Henthorne 9440dfb66c Do not show profile name changes on first update. 2020-07-17 09:42:13 -04:00
Alan Evans 7a019eee19 Updated language translations. 2020-07-16 16:21:02 -03:00
Greyson Parrelli 93f56a5dc8 Bump version to 4.66.7 2020-07-16 10:40:04 -04:00
Greyson Parrelli 68264228b8 Updated language translations. 2020-07-16 10:33:33 -04:00
Greyson Parrelli 66c1b8e26c Fix contact icon tint issues on older android versions. 2020-07-16 10:27:23 -04:00
Cody Henthorne 5776c048ea Do not update threads that do not exist. 2020-07-16 09:27:41 -04:00
Greyson Parrelli 76dd09bc50 Handle null profile names better. 2020-07-16 08:34:53 -04:00
Greyson Parrelli 73d18d3abd Bump version to 4.66.6 2020-07-15 17:12:37 -04:00
Greyson Parrelli c1c9d0c8a3 Updated language translations. 2020-07-15 17:12:09 -04:00
Cody Henthorne 64420ead7c Show Profile Name Change update messages. 2020-07-15 16:15:15 -04:00
Alan Evans 6d035c6888 Allow sending of group v2 updates to inactive groups. 2020-07-15 12:31:59 -03:00
Alan Evans 833ca8cce9 Add disable GV2 creation option to internal preferences UI. 2020-07-15 12:28:47 -03:00
Ehren Kret d02d506b13 Add force refresh of remote values to internal preferences UI. 2020-07-15 12:16:07 -03:00
Alan Evans f306056e5d Enable lint StopShip comments. 2020-07-15 12:04:05 -03:00
Greyson Parrelli 58ec669d15 Fix quote attachmentV3 usage. 2020-07-14 19:43:17 -04:00
Greyson Parrelli d1b61bfed3 Add indicator for system contacts. 2020-07-14 10:37:09 -04:00
Greyson Parrelli 325e0c6781 Bump version to 4.66.5 2020-07-14 10:26:15 -04:00
Greyson Parrelli 8d66cd52b5 Updated language translations. 2020-07-14 10:25:46 -04:00
Greyson Parrelli 4b9277629c Fix issue with tracking registration state. 2020-07-13 19:00:44 -04:00
Greyson Parrelli 6515a6188b Bump version to 4.66.4 2020-07-13 11:01:18 -04:00
Greyson Parrelli 8b3ca52502 Updated language translations. 2020-07-13 11:00:34 -04:00
Alan Evans fae003e085 Do not sync group v2 recipients that we do not have the master key for. 2020-07-13 11:52:06 -03:00
Greyson Parrelli 4b961d2d8f Simplify PIN opt-out code. 2020-07-13 09:29:17 -04:00
Greyson Parrelli e27fc512b4 Add a migration for users of the previous PIN opt-out flow. 2020-07-13 08:53:02 -04:00
Greyson Parrelli 8f0f600b6b Bump version to 4.66.3 2020-07-11 11:42:51 -04:00
Greyson Parrelli 5950610690 Updated language translations. 2020-07-11 11:42:51 -04:00
Greyson Parrelli fce3df0c82 Update pin opt-out strings and behavior. 2020-07-11 11:42:51 -04:00
Greyson Parrelli e2021231c6 Bump version to 4.66.2 2020-07-10 17:23:50 -04:00
Greyson Parrelli f61dd7509e Updated language translations. 2020-07-10 17:23:50 -04:00
Greyson Parrelli db2b64e58c Update PIN opt-out strings. 2020-07-10 17:23:50 -04:00
Alan Evans d70999c386 Add storage force push internal option. 2020-07-10 17:23:50 -04:00
Alan Evans eb6ecc59ab Consolidate duplicated group send job logic. 2020-07-10 17:23:50 -04:00
Cody Henthorne 1e0e2fadfd Improve scroll to last position behavior. 2020-07-10 17:23:50 -04:00
Alan Evans 4325f714b9 Silent group update send job for profile key rotation. 2020-07-10 17:23:50 -04:00
Alan Evans 137cd45497 Hide "Add to a group" if you don't have any groups. 2020-07-10 17:23:50 -04:00
Alan Evans f3dbe4416f Add lint to detect non-numeric version code checks. 2020-07-10 17:23:50 -04:00
Greyson Parrelli 7fb55c0f51 Keep borderless property when forwarding media. 2020-07-10 17:23:50 -04:00
Greyson Parrelli fdc6cbc507 Bump version to 4.66.1 2020-07-09 19:10:27 -04:00
Greyson Parrelli 072085ae82 Updated language translations. 2020-07-09 19:09:54 -04:00
Greyson Parrelli 04a8996348 Add the ability to opt out of PINs. 2020-07-09 19:07:21 -04:00
Cody Henthorne c26dcc2618 Fix theming issues with snackbars and alert dialogs. 2020-07-09 19:07:21 -04:00
Alan Evans a4dc340bbc Handle empty group change byte array. 2020-07-09 19:07:21 -04:00
Cody Henthorne 3c069fb588 Enable Media Preview to respond to media changes. 2020-07-09 19:07:21 -04:00
Fumiaki Yoshimatsu 1fe38f5ed1 Fix pen/highlighter tool single tap.
Fixes #9745
2020-07-09 11:25:10 -03:00
Greyson Parrelli 841c9424e9 Remove GV2 flag requirement for WakeGroupV2Job. 2020-07-09 10:02:59 -04:00
Greyson Parrelli 9c44a0c7d3 Don't run ProfileUploadJob if you're not registered. 2020-07-09 07:57:37 -04:00
Greyson Parrelli 2883d2eb31 Enable video call PiP. 2020-07-09 07:50:38 -04:00
Greyson Parrelli f5aade943e Bump version to 4.66.0 2020-07-08 17:15:10 -04:00
Greyson Parrelli d17c3f39d0 Updated language translations. 2020-07-08 17:12:19 -04:00
Alan Evans 9ac9ace6b8 Groups V2 state comparison and gap handling. 2020-07-08 17:12:19 -04:00
Greyson Parrelli c9d2cef58d Add support for sending borderless keyboard stickers. 2020-07-08 16:51:30 -04:00
Alan Evans a9e30eefdc Prevent adding self to group by number.
Fixes #9821
2020-07-08 16:51:30 -04:00
Cody Henthorne 1a895db9bd Finalize support for calling with system PIP. 2020-07-08 16:51:30 -04:00
Alan Evans a955bc3b9b Fix single line text input for group names. 2020-07-08 16:51:30 -04:00
Alan Evans 96e888a4f5 Remove versioned profiles feature flag. 2020-07-08 16:51:30 -04:00
Alan Evans 99ff0c1e3c Ensure direct add members to a group removes any matching pending. 2020-07-08 16:51:30 -04:00
Alan Evans 599e89b1f9 Fix audio waveform RTL rendering.
Fixes #9823
2020-07-08 16:51:30 -04:00
Greyson Parrelli 33c527f15e Remove the final KBS feature flags. 2020-07-08 16:51:30 -04:00
Greyson Parrelli eb02dacfdc Convert HEIC/HEIF to JPEG. 2020-07-08 16:51:30 -04:00
Alan Evans e6a0e5b858 Add internal preferences under Advanced behind feature flag.
Initially for GV2 testing.
2020-07-08 16:51:30 -04:00
Greyson Parrelli 545ba80697 Add support for borderless images.
Added support for 'borderless' images. Basically images that we'd like to render 
as if they were stickers, even though they're not stickers. On iOS, this will be 
stuff like memoji and bitmoji. On Android, in my initial pass, I've just added 
support for Giphy stickers. However, we can also detect bitmoji and keyboard 
stickers in the future. This is kind of a 'best effort' thing, so as long as we 
support receiving, we can just add sending support for more things as we go.
2020-07-08 16:51:30 -04:00
Cody Henthorne 1e250ee95c Add Calling Requests. 2020-07-08 16:51:30 -04:00
Greyson Parrelli 5a12eedc2c Prevent possible deadlock with LiveRecipientCache.
Thread A: DirectoryHelper#updateContactsDatabase() acquires database lock
Thread B: LiveRecipientCache#getSelf() acquires lock on LiveRecipientCache
Thread A: DirectoryHelper#updateContactsDatabase() calls Recipient.externalContact(), which eventually needs LiveRecipientCache lock
Thread B: Needs to read the database (e.g. line 120) to get information about itself

So A has the DB lock but needs the LiveRecipientCache lock, and B has
the LiveRecipientCache lock but needs the DB lock.

In general, we need to avoid acquiring any new locks in a transaction,
but for now, this specific instance looks like it could be solved by
using a unique lock for LiveRecipientCache#getSelf().
2020-07-08 16:51:30 -04:00
Greyson Parrelli 5605fde777 Rename the UUID flag to be more explicit. 2020-07-08 16:51:30 -04:00
Greyson Parrelli 9ac142688a Increase the max PIN reminder interval to 4 weeks. 2020-07-08 16:51:30 -04:00
Greyson Parrelli 2791790bf5 Implement new CDS changes. 2020-07-08 16:51:30 -04:00
Cody Henthorne 1752972be9 Update delete for everyone functionality to match requirements. 2020-07-08 16:51:30 -04:00
Greyson Parrelli c877aba09f Use resolved recipients in the conversation list. 2020-07-08 16:51:30 -04:00
Greyson Parrelli 70e33518a9 Do registration checks for new numbers during group creation. 2020-07-08 16:51:30 -04:00
Greyson Parrelli cb81a9f783 Disallow 'visually empty' profile names. 2020-07-08 16:51:30 -04:00
Greyson Parrelli b6b499d865 Refresh recipients outside of a transaction for storage service. 2020-07-08 16:51:30 -04:00
Alan Evans 6704ad8193 Do not show update messages for profile key updates. 2020-07-08 16:51:30 -04:00
Greyson Parrelli 942628a261 Improve ConversationListDataSource logging. 2020-07-08 16:51:30 -04:00
Greyson Parrelli 4ea8bac10d Re-enable view prefetching. 2020-07-08 16:51:30 -04:00
Alan Evans eafccc5721 Add GV2 copy for the unknown editor. 2020-06-30 14:46:10 -03:00
Greyson Parrelli a01bec3a11 Bump version to 4.65.2 2020-06-30 11:38:26 -04:00
Greyson Parrelli 3868175b85 Updated language translations. 2020-06-30 11:37:44 -04:00
Greyson Parrelli 904cb01067 Use the BlobProvider in the contact and group sync jobs. 2020-06-30 11:17:29 -04:00
Alan Evans 5c0cb425a6 Only sync V1 groups with linked devices. 2020-06-30 10:17:42 -03:00
Cody Henthorne 9dbb2ef630 Ensure user knows Safety Number Change Dialog list is scrollable when necessary. 2020-06-26 16:36:01 -04:00
Alan Evans bafd2817ee Fix pending member activity background color. 2020-06-26 17:29:05 -03:00
Greyson Parrelli 3380293923 Bump version to 4.65.1 2020-06-26 15:40:23 -04:00
Greyson Parrelli a549c1ec8b Updated language translations. 2020-06-26 15:38:48 -04:00
Greyson Parrelli ad84997ce0 Fix display of quotes in 'All Media' view. 2020-06-26 15:33:08 -04:00
Alan Evans 42e2576813 Prevent repeat attempts when waveforms cannot be generated. 2020-06-26 16:18:27 -03:00
Cody Henthorne 31b995fa98 Retrieve profiles on mismatch to notify user of updates quicker. 2020-06-26 14:25:39 -03:00
Greyson Parrelli 0364bec995 Allow skipping if you hit a network error during PIN restore. 2020-06-26 14:25:39 -03:00
Alan Evans aa39f3d0a3 Fix create new pin option in registration flow. 2020-06-26 13:29:00 -03:00
Greyson Parrelli db545f43ea Remove profile name reminder megaphone. 2020-06-26 11:52:00 -04:00
Cody Henthorne bbe003a454 Improve messaging and UX around safety number changes. 2020-06-26 11:10:54 -04:00
Greyson Parrelli 819f0f68f6 Fix issue with some search results returning empty. 2020-06-26 10:46:44 -04:00
Greyson Parrelli 8c0160937b Fix crash with 'select all' in conversation list.
Fixes #9790
2020-06-26 10:12:16 -04:00
Cody Henthorne 6de789dfe3 Prevent attachment download button re-animation. 2020-06-26 10:10:34 -04:00
Greyson Parrelli afa2bb3bf5 Disallow swipe actions in search mode.
Fixes #9771
2020-06-26 10:08:01 -04:00
Greyson Parrelli 89e66c0741 Bump version to 4.65.0 2020-06-25 18:14:54 -04:00
Greyson Parrelli 0dc4afba99 Updated language translations. 2020-06-25 18:14:54 -04:00
Greyson Parrelli 152578e576 Add reserved job runners for inbound and outbound messages. 2020-06-25 18:14:54 -04:00
Greyson Parrelli 63d6ab6fa7 Throttle conversation list update frequency.
This helps fast phones process messages faster by reducing contention on
the database while processing a large batch of messages.
2020-06-25 18:14:54 -04:00
Greyson Parrelli 75c8c59d78 Reduce notification update interval. 2020-06-25 18:14:54 -04:00
Greyson Parrelli 87a59b6a9b Add support for memory-only jobs. 2020-06-25 18:14:54 -04:00
Alan Evans 2001fa86cf Log capabilities. 2020-06-25 18:14:54 -04:00
Alan Evans 52747782a7 Full screen avatar circle to square shape transition. 2020-06-25 18:14:54 -04:00
Fumiaki Yoshimatsu 66f2668326 Do not cache locale in each conversation object.
Fixes #9751
2020-06-25 18:14:54 -04:00
Cody Henthorne b262efc24c Clear up warnings in string resource file. 2020-06-25 18:14:54 -04:00
Alan Evans ce7ad76447 Cycle Versioned Profiles feature flag. 2020-06-25 08:29:48 -04:00
Greyson Parrelli 9e98b6616e Log job run time. 2020-06-25 08:29:48 -04:00
Alan Evans f4c9eaa904 Remove some unused resources. 2020-06-25 08:29:48 -04:00
Greyson Parrelli f8a0988e5f Various JobManager performance improvements. 2020-06-25 08:29:48 -04:00
Greyson Parrelli bf919207ed Various logging improvements.
* Improve lifecycle logging.
* Remove 'action bar' from base activity names.
* Remove some unnecessary glide logs.
2020-06-25 08:29:48 -04:00
Greyson Parrelli dac6b5c992 Bump version to 4.64.7 2020-06-24 20:09:31 -04:00
Greyson Parrelli 7f8043777e Updated language translations. 2020-06-24 20:09:00 -04:00
Greyson Parrelli 854b3feb36 Reduce verbosity of job logs. 2020-06-24 20:00:42 -04:00
Greyson Parrelli 22447e6ddb Fix theming issue with snackbar. 2020-06-24 20:00:42 -04:00
Alan Evans be2ec36e1f Fix clipping issues with archive icon.
Fixes #8344
2020-06-24 20:00:12 -04:00
Greyson Parrelli 98cf16479d Bump version to 4.64.6 2020-06-24 10:58:13 -04:00
Greyson Parrelli 584735cbd0 Updated language translations. 2020-06-24 10:57:45 -04:00
Alan Evans 3741493cb7 Remove frame rate reporter and unused FPS ringbuffer. 2020-06-24 11:44:35 -03:00
Greyson Parrelli 4ea861fe5c Improve 'mark all read' performance. 2020-06-24 10:34:52 -04:00
Jim Gustafson cd3df4d3c1 Update to ringrtc v2.2.0 2020-06-24 09:50:43 -04:00
Alan Evans 881a1edccb Bump version to 4.64.5 2020-06-22 10:53:52 -03:00
Alan Evans 1b7b574289 Updated language translations. 2020-06-22 10:50:27 -03:00
Alan Evans d1d7498447 Fix text colors when system theme doesn't match. 2020-06-22 10:02:18 -03:00
Greyson Parrelli 50c18727e7 Bump version to 4.64.4 2020-06-21 12:23:31 -04:00
Greyson Parrelli e9bfde470a Updated language translations. 2020-06-21 12:23:10 -04:00
Greyson Parrelli 68f718a210 Fix issue with conversation list times not updating.
Just started calling notifyDataSetChanged() in onResume() to provide
some sort of time update regularity.
2020-06-21 12:20:18 -04:00
Greyson Parrelli c3e528ad4b Bump version to 4.64.3 2020-06-19 19:17:16 -04:00
Greyson Parrelli 28af97c400 Updated language translations. 2020-06-19 19:17:16 -04:00
Jim Gustafson c2e4c343ab Update to ringrtc v2.1.1 2020-06-19 19:12:59 -04:00
Cody Henthorne 8a78589c2f Fix light navigation buttons in conversation settings screens. 2020-06-19 16:53:38 -04:00
Alan Evans 841ee18435 Add default option to message vibrate for pre API26. 2020-06-19 13:08:54 -03:00
Greyson Parrelli 71f54701d2 Add additional safeguards around disappearing messages. 2020-06-19 10:17:23 -04:00
Alan Evans 1c99939dfa Bump version to 4.64.2 2020-06-18 17:30:38 -03:00
Alan Evans 50462cecd0 Updated language translations. 2020-06-18 17:29:20 -03:00
Cody Henthorne aa6a32f023 Make conversation footer always show. 2020-06-18 16:14:38 -04:00
Alan Evans c4dc9064e3 Handle Attachment Keyboard selection of a too large item. 2020-06-18 15:55:26 -03:00
Alan Evans bc5be10a0e Respect emoji config on conversation banner title. 2020-06-18 15:39:02 -03:00
Alan Evans 98d9b57379 Add copy to bottom sheet for Note to Self. 2020-06-18 14:34:30 -03:00
Cody Henthorne 021a16050a Stop back transition jank from avatar viewer to settings. 2020-06-18 13:16:08 -04:00
Alan Evans 555104aff0 Make message button navigate back if launched from the conversation. 2020-06-18 14:00:06 -03:00
Alan Evans 95d63b78f4 Add call and message buttons to recipient bottom sheet.
And insecure call button for non-registered contacts.
2020-06-18 13:23:46 -03:00
Alan Evans 80f9e1f4f1 Fix not able to get to archived conversations when all archived. 2020-06-18 12:23:20 -03:00
Alan Evans a77997a4de Fix margins for "No groups in common" & unregistered case. 2020-06-18 09:49:22 -03:00
Alan Evans ec4eb8e2a9 Bump version to 4.64.1 2020-06-17 17:54:58 -03:00
Alan Evans 1bdeade71e Updated language translations. 2020-06-17 17:53:19 -03:00
Greyson Parrelli 629ba105cb Detect real age of call request by using server timestamps. 2020-06-17 17:53:18 -03:00
Alan Evans 891a1af995 Show Note to Self for local number recipient preferences. 2020-06-17 17:49:44 -03:00
Cody Henthorne 0fbc6ac151 Revert improperly removed code for Message Request footer. 2020-06-17 17:49:43 -03:00
Alan Evans a6384d1b73 Add insecure call ability to recipient settings. 2020-06-17 17:49:43 -03:00
Alan Evans 2fb9514890 Respect emoji setting in profile/group name editing. 2020-06-17 17:49:43 -03:00
Alan Evans fe89794505 Hide recipient subtitle if no name/username set. 2020-06-17 17:49:43 -03:00
Cody Henthorne 08800c9faf Make Message Details update views in more situations. 2020-06-17 17:49:43 -03:00
Cody Henthorne 469a4700d2 Fix improper tinting on screens when using FallbackPhoto. 2020-06-17 17:49:43 -03:00
Alan Evans 6707f974a5 Remove NewGroupUI FeatureFlag. 2020-06-17 17:49:43 -03:00
Alan Evans c122cada2b Change call button shade. 2020-06-17 17:49:43 -03:00
Alan Evans 96f02d8c95 Hide some views for Note to Self conversation. 2020-06-17 17:49:43 -03:00
Greyson Parrelli dd717b60b8 Bump version to 4.64.0 2020-06-16 23:47:15 -04:00
Greyson Parrelli 3c20c7f4b4 Updated language translations. 2020-06-16 23:46:41 -04:00
Cody Henthorne 1a09e70a04 Remove old Message Details. 2020-06-16 19:30:35 -04:00
Alan Evans 027453bbd2 Prevent IllegalStateException on recipient bottom sheet. 2020-06-16 19:30:35 -04:00
Greyson Parrelli b621efa4a5 Don't prefetch views for the conversation list. 2020-06-16 19:30:35 -04:00
Cody Henthorne 2915e4698c Show registration rate limit error messaging. 2020-06-16 19:30:35 -04:00
Cody Henthorne b687b1a4c5 Fix repeat alerts by using explicit reminder intent. 2020-06-16 19:30:35 -04:00
Alan Evans b53827f32b Manage recipient activity. 2020-06-16 19:30:35 -04:00
Cody Henthorne d9641128a8 Refresh Message Details screen. 2020-06-16 19:30:35 -04:00
Alan Evans dfb5562142 Use group manager for MMS groups. 2020-06-16 19:30:35 -04:00
Jim Gustafson d467c04749 Ensure speaker off at start of any call 2020-06-16 19:30:35 -04:00
Greyson Parrelli 3d7cffef2b Remove Message Requests feature flag. 2020-06-16 19:30:35 -04:00
Alex Hart f2fe81d9b5 Fix conversation jumping when loading at last scroll position. 2020-06-16 19:30:35 -04:00
Greyson Parrelli cf98a22269 Add placeholder support for ConversationListAdapter. 2020-06-16 19:30:35 -04:00
Alex Hart 49f75d7036 Migrate ConversationList to paging library and apply abstractions to conversation. 2020-06-16 19:30:35 -04:00
Greyson Parrelli ce940235b0 Optimistically fetch profiles. 2020-06-16 19:30:35 -04:00
Alan Evans f5626f678d Make CustomNotificationsDialogFragment work with recipients. 2020-06-16 19:30:35 -04:00
Alan Evans b3a59c3946 Use recipient display name in recipient bottom sheet. 2020-06-16 19:30:35 -04:00
Fumiaki Yoshimatsu 93c390c4fc Don't send a read receipt when the recipient is blocked.
Fixes #9610
2020-06-16 19:30:35 -04:00
Cody Henthorne 941ab5a98f Prevent avatar from showing a start of outgoing video call. 2020-06-16 19:30:35 -04:00
Jim Gustafson 2ecdf803c0 Update to ringrtc v2.1.0 2020-06-16 19:30:35 -04:00
Cody Henthorne 5b2a399392 Return to previous scroll position when returning to a conversation. 2020-06-16 19:30:35 -04:00
Alex Hart a9ea1d7606 Utilize DayNight theme when launching the app. 2020-06-12 11:36:15 -03:00
Greyson Parrelli 1ce8ac2de6 Light refactor of SignalStore. 2020-06-12 11:36:15 -03:00
Greyson Parrelli e2019579fb Bump version to 4.63.3 2020-06-12 10:09:20 -04:00
Greyson Parrelli fb3c6e56ee Updated language translations. 2020-06-12 10:08:51 -04:00
Greyson Parrelli 3fad007ae0 Cancel typing jobs when you send a group message. 2020-06-12 10:06:20 -04:00
Greyson Parrelli 8891b6c930 Properly throw UnregisteredUserException in SignalServicePipe. 2020-06-11 12:08:40 -04:00
Alan Evans 400c592acf Display 'Unknown group' for groups with no name. 2020-06-10 17:17:47 -03:00
Alex Hart e13f3254ad Fix message jump-to-position. 2020-06-10 17:06:40 -03:00
Greyson Parrelli bf40a07bb9 Bump version to 4.63.2 2020-06-10 14:43:24 -04:00
Greyson Parrelli 8f3a6b8479 Update unblock string. 2020-06-10 14:37:03 -04:00
Greyson Parrelli 7642b7cc72 Fix issue with typing indicators in blocked groups. 2020-06-10 14:28:12 -04:00
Greyson Parrelli e12ea60d85 Bump version to 4.63.1 2020-06-10 12:48:15 -04:00
Greyson Parrelli 0b13c4aed6 Updated language translations. 2020-06-10 12:48:15 -04:00
Alan Evans 47919382e9 Show 'Add to another group' when launched from a group context. 2020-06-10 12:59:57 -03:00
Greyson Parrelli d60d67ee7e Set contact colors more aggressively. 2020-06-10 10:49:22 -04:00
Alan Evans 559aa687a5 Show group participants menu item on a MMS group. 2020-06-10 11:32:50 -03:00
Cody Henthorne bc0761f002 Fix navigate up behavior for Conversations. 2020-06-10 10:28:34 -04:00
Alan Evans c0c2fc0eba When there are no recipients left on group create screen toast and return to list. 2020-06-10 09:07:12 -03:00
Alan Evans 44fe43c74c Hide 'Add to a group' for non-registered users. 2020-06-10 08:54:57 -03:00
Alan Evans 53a2a5d693 Prevent highlighter opacity affecting blur tool. 2020-06-09 23:56:03 -03:00
Greyson Parrelli 2334c26cbb Bump version to 4.63.0 2020-06-09 16:56:57 -04:00
Greyson Parrelli 0b6dde46d9 Updated language translations. 2020-06-09 16:55:50 -04:00
Greyson Parrelli 98d9d81aff Insert receipts in a transaction. 2020-06-09 15:11:37 -04:00
Greyson Parrelli 736a62b632 Update strings related to message requests. 2020-06-09 14:12:52 -04:00
Cody Henthorne cea6a83d8a Show member count in contact selection list. 2020-06-09 13:32:48 -04:00
Greyson Parrelli 2751fd7efc Retrieve profiles in parallel. 2020-06-09 12:47:11 -04:00
Cody Henthorne 2822042eeb Show recent groups in Add to Groups screen. 2020-06-09 12:13:13 -04:00
Cody Henthorne dc46d88ddd Provide two ways of listening for thread/message db updates. 2020-06-09 11:52:58 -04:00
Alex Hart e04f76b558 Fix issue where invalid PagedList objects were passed to ConversationAdapter. 2020-06-09 12:37:19 -03:00
Alan Evans a758056494 Take highlighter down from 50% to 37.5% opacity. 2020-06-09 12:35:53 -03:00
Alan Evans 1ecdea5db3 Reinstate highlighter under drawing menu. 2020-06-09 12:10:40 -03:00
Alan Evans e1bb773d85 Add 'Add to a group' button to bottom sheet. 2020-06-09 12:09:59 -03:00
Alan Evans 7e934eff5d Make quotes not hold strong references to attachments. 2020-06-09 12:07:41 -03:00
Greyson Parrelli cfdf5603af Bump version to 4.62.4 2020-06-09 00:39:55 -04:00
Greyson Parrelli 45bfb8c6b6 Updated language translations. 2020-06-09 00:38:19 -04:00
Alex Hart 65608a51b8 Fix API 19 crash by using different resource. 2020-06-09 00:33:38 -04:00
Greyson Parrelli b6314597fe Bump version to 4.62.3 2020-06-08 16:32:08 -04:00
Greyson Parrelli 20a588199a Updated language translations. 2020-06-08 16:32:00 -04:00
Greyson Parrelli 59916f1e95 Add 'Add to contacts' button to bottom sheet. 2020-06-08 16:07:14 -04:00
Alan Evans 8b91f8f9e7 Disable disappearing messages option and remove from menu. 2020-06-08 12:31:55 -03:00
Alex Hart cbc3cce66f Fix API 19 drawable crash in ManageGroupFragment. 2020-06-08 11:34:39 -03:00
Alex Hart b4b63b5860 Add auto-mirroring to ic_forward_outline. 2020-06-08 10:23:43 -03:00
Alex Hart b9ae15a890 Fix group name RTL alignment. 2020-06-08 10:21:55 -03:00
Greyson Parrelli d955389c46 Bump version to 4.62.2 2020-06-07 22:05:02 -04:00
Greyson Parrelli 975eb885c1 Updated language translations. 2020-06-07 22:05:02 -04:00
Alan Evans a3aed96757 Sort contacts without names after contacts with names. 2020-06-07 22:05:02 -04:00
Alan Evans dc70bfabaf Lighter ultramarine + in dark mode. 2020-06-07 22:05:02 -04:00
Greyson Parrelli 6932340671 Add ability to copy a number via long-press. 2020-06-07 19:59:42 -04:00
Alan Evans f6637b7caf Restore mute in conversation menu. 2020-06-07 19:59:42 -04:00
Alan Evans 4f4be44caa Load identities in transaction. 2020-06-07 19:59:42 -04:00
Greyson Parrelli 7832497ba7 Shorten logging in ConversationActivity. 2020-06-07 19:59:42 -04:00
Alex Hart 7d06e2395f Rework how ConversationFragment RecyclerView responds to data updates. 2020-06-07 19:59:42 -04:00
Greyson Parrelli 3a479d7eef Reduce database notifications for disappearing conversations. 2020-06-07 19:59:42 -04:00
Greyson Parrelli 8fe8a1e9ee Put refresh and upload profile jobs in the same queue. 2020-06-07 19:59:42 -04:00
Alan Evans 2d8b2e7fb0 Transitions for group settings. 2020-06-07 19:59:42 -04:00
Alan Evans 9c0365f92c Open group settings from group avatar click. 2020-06-07 19:59:42 -04:00
Greyson Parrelli b48abb08d2 Show custom notifications for API < 26. 2020-06-07 19:59:42 -04:00
Alan Evans d8f3e032c7 Fix group name clearing after avatar change. 2020-06-07 19:59:42 -04:00
Alan Evans 8dbcb255ad Hide Block and Leave options when not available in group settings, add unblock. 2020-06-07 19:59:42 -04:00
Greyson Parrelli db06cbbc86 Remove unnecessary recipient refreshes. 2020-06-07 19:59:42 -04:00
Cody Henthorne 98ab23c1a3 Make Custom Notification dialog dismiss itself on up press. 2020-06-07 10:23:41 -04:00
Cody Henthorne d0ca9ba6a6 Make text button color responsive to theme. 2020-06-07 09:43:14 -04:00
Alan Evans b242368675 Remove group members button. 2020-06-07 09:31:18 -03:00
Alan Evans 664527ce63 Fix sort order for group members. 2020-06-07 08:25:31 -03:00
Alan Evans 99e4f80be0 Allow whole row selection for Shared media in group settings. 2020-06-07 08:12:25 -03:00
Alan Evans 702dae9fcd Fix double tap required for "See all" media in group settings. 2020-06-07 07:47:28 -03:00
Alan Evans 48fe1ba559 Fix group settings divider shade in dark mode. 2020-06-07 07:42:28 -03:00
Greyson Parrelli 382ac7ba0d Bump version to 4.62.1 2020-06-06 20:28:18 -04:00
Greyson Parrelli a46f47f352 Updated language translations. 2020-06-06 20:27:48 -04:00
Greyson Parrelli e984d8a42c Change Gif -> GIF. 2020-06-06 20:27:22 -04:00
Greyson Parrelli 554bad6b8d Improve DB access in group sends. 2020-06-06 20:25:02 -04:00
Jim Gustafson ed13c97ad7 Handle legacy hangup properly. 2020-06-06 20:25:02 -04:00
Greyson Parrelli d33873d59a Fix possible crash with null thread body. 2020-06-06 20:25:02 -04:00
Greyson Parrelli 1234899ea1 Add support for non-blocking media sends. 2020-06-06 20:25:02 -04:00
Cody Henthorne 13027dc44b Fix leaking MessageDetailsActivity via list items. 2020-06-06 20:25:02 -04:00
Cody Henthorne 5b4d74b7fe Move group resolution for conversations to background LiveData. 2020-06-06 20:25:02 -04:00
Alan Evans 18c7bc2b5b Prevent edit of a group post leave. 2020-06-06 20:25:02 -04:00
Alan Evans bbbee0f372 Fix group create arrow for RTL. 2020-06-06 20:25:02 -04:00
Alex Hart cf9d090154 Start Paging @ Unread count instead of -1. 2020-06-06 20:25:02 -04:00
Alan Evans 718471917f Separate text only message layouts. 2020-06-06 20:25:02 -04:00
Greyson Parrelli bb97407cde Bump version to 4.62.0 2020-06-05 22:04:18 -04:00
Greyson Parrelli 92ce678e29 Updated language translations. 2020-06-05 22:04:16 -04:00
Cody Henthorne e100aea2c7 Preserve scroll position in Message Details on update. 2020-06-05 21:46:04 -04:00
Greyson Parrelli fea3b6cb4a Don't show 'conversation settings' for groups. 2020-06-05 21:46:04 -04:00
Cody Henthorne afbc132faa Fix conversation item and data source memory leaks. 2020-06-05 21:46:04 -04:00
Alan Evans b27198286d MMS proof new group UI. 2020-06-05 21:46:04 -04:00
Greyson Parrelli ac93d81032 Remove pins4all feature flag. 2020-06-05 21:46:04 -04:00
Alan Evans 9981e5ca76 Enable new group UI. 2020-06-05 20:19:03 -03:00
Cody Henthorne 7dd3efeb53 Remove listeners when detaching conversation item views. 2020-06-05 19:29:55 -03:00
Greyson Parrelli d38d702adf Parallelize group sends. 2020-06-05 18:10:50 -04:00
Alex Hart 04a000a8a8 Always display labels in contact search. 2020-06-05 15:16:55 -03:00
Fumiaki Yoshimatsu 3bbf0741ee Use localized string for Phone number.
Fixes #9626
2020-06-05 15:01:20 -03:00
Fumiaki Yoshimatsu e9a336100b Display backup date in users locale on restore.
Fixes #9693
2020-06-05 15:01:20 -03:00
Cody Henthorne fb600e9829 Update SMS/MMS as sending when retrying failed send.
This was only impacting SMS/MMS as Push already reset the status.
2020-06-05 13:46:25 -04:00
Alex Hart 4a455ff958 Implement new Add Members UI. 2020-06-05 13:44:02 -03:00
Cody Henthorne 707e238e5c Make borderless button style responsive to theme. 2020-06-05 12:01:00 -04:00
Alan Evans 90f22a4b66 Include face position and projection matrix into elements matrix. 2020-06-04 19:49:22 -03:00
Alex Hart b4f134adf7 Add more descriptive messages for media notifications and chat previews. 2020-06-04 13:13:42 -03:00
Greyson Parrelli 1e00fc6149 Bump version to 4.61.6 2020-06-04 10:21:23 -04:00
Greyson Parrelli f52133a69c Updated language translations. 2020-06-04 10:21:23 -04:00
Alan Evans 91b142e0d9 Fix waveform array out of bounds. 2020-06-04 10:21:10 -04:00
Greyson Parrelli 26a9dd98c1 Bump version to 4.61.5 2020-06-03 19:01:03 -04:00
Greyson Parrelli 99e38e1d23 Updated language translations. 2020-06-03 18:58:34 -04:00
Greyson Parrelli a2d8a25fd9 Blur UI tweaks. 2020-06-03 18:51:38 -04:00
Alan Evans d86d625bcc Smoother blur rendering. 2020-06-03 19:47:51 -03:00
Greyson Parrelli 18e3fb6609 Fix string format. 2020-06-03 17:19:32 -04:00
Greyson Parrelli da33ba0ed5 Update blur UI. 2020-06-03 17:12:47 -04:00
Greyson Parrelli 66f021d01a Fix issue where rail wasn't showing in some situations. 2020-06-03 17:12:47 -04:00
Greyson Parrelli 40231ea45f Fix issue with view-once toggle and face blurring. 2020-06-03 17:12:42 -04:00
Alex Hart cd80a47c04 Made edit profile save button move with the keyboard. 2020-06-03 17:12:27 -04:00
Alan Evans 1033bd7bda Blur faces rotation and crop and zoom support. 2020-06-03 14:02:24 -03:00
Greyson Parrelli b4f60f3acb Bump version to 4.61.4 2020-06-03 06:40:09 -04:00
Greyson Parrelli bed3b571cc Updated language translations. 2020-06-03 06:39:34 -04:00
Greyson Parrelli c8dd4e5254 Added support for blurring faces.
Co-authored-by: Alan Evans <alan@signal.org>
2020-06-03 06:39:20 -04:00
Alan Evans 514048171b Add Image Editor support for blur mask layer. 2020-06-03 03:33:06 -03:00
Greyson Parrelli 32e9901592 Bump version to 4.61.3 2020-06-02 19:22:22 -04:00
Greyson Parrelli d83f86a469 Revert "Make notifications and chat previews for media messages more descriptive."
This reverts commit a3f9737e63.
2020-06-02 19:19:30 -04:00
Greyson Parrelli 403d53586c Bump version to 4.61.2 2020-06-02 17:40:56 -04:00
Greyson Parrelli 6acae58694 Updated language translations. 2020-06-02 17:33:41 -04:00
Alex Hart a3f9737e63 Make notifications and chat previews for media messages more descriptive. 2020-06-02 17:34:50 -03:00
Cody Henthorne 263af7c139 Add registration lock status to support email. 2020-06-02 16:14:19 -04:00
Alex Hart 7f2439f1e9 Fix contact selection behavior when searching and clear search on selection. 2020-06-02 16:27:04 -03:00
Alex Hart ae87d23003 Always use the new group settings screen if the flag is enabled. 2020-06-02 16:09:48 -03:00
Alex Hart 3192cc0aac Add outlined view-once close icon. 2020-06-02 16:05:16 -03:00
Alex Hart 6102e9aa72 Apply better coordinatorlayout animation and RTL support. 2020-06-02 15:02:35 -03:00
Alan Evans f4a152b0fe Fetch own profile after GV2 feature flag is enabled, improve GV2 capability check. 2020-06-02 11:48:40 -03:00
Greyson Parrelli 2b11bca7dc Guard against possible invalid conversation data loads. 2020-06-02 10:20:55 -04:00
Artem Varaksa 07d19f38e3 Fix typos in logging for remote delete. 2020-06-02 10:22:29 -03:00
Greyson Parrelli cd228c439e Be more explicit with the ID we use for account updates. 2020-06-02 09:03:54 -04:00
Alan Evans 7a859c8961 For smaller width devices, use original 210dp for audio messages. 2020-06-02 09:32:59 -03:00
Alan Evans 543f38c75d Fix Wave form IOException thread issue. 2020-06-02 07:38:15 -03:00
Greyson Parrelli f7b150f2d2 Bump version to 4.61.1 2020-06-01 17:43:05 -04:00
Greyson Parrelli 11328f643f Updated language translations. 2020-06-01 17:43:05 -04:00
Greyson Parrelli f270a6b8c4 Fix potential crash by removing an unnecessary column.
The column I removed is already in the recipient half of the projection.
Having two representations of the groupId made reading the groupId out
of the cursor non-deterministic, and when compounded with another bug,
could cause a crash if one of them was null.
2020-06-01 17:43:05 -04:00
Alan Evans 3fec23fd36 Show remaining time on wave form view and cache wave form in database. 2020-06-01 17:43:05 -04:00
Alex Hart e01838e996 Fix text size for pending members. 2020-06-01 17:43:05 -04:00
Greyson Parrelli f70e41e7cd Don't allow account record updates to delete our profile key. 2020-06-01 17:43:05 -04:00
Greyson Parrelli c4ec0c9897 Handle devices disallowing start of FcmFetchService.
Some devices are overzealous with battery management and disallow
starting services even when they're in response to a high-priority FCM
message (which should be allowed). So in these situations, we just
fall back to what we were doing before.
2020-06-01 17:43:05 -04:00
Greyson Parrelli 989b071a6d Ignore contacts that don't have a phone number. 2020-06-01 17:43:05 -04:00
Greyson Parrelli c39751f9db Add info about play services to the debug log. 2020-06-01 17:43:05 -04:00
jimio-signal dbf74a2234 Update copyright in README.md 2020-05-31 10:39:19 -07:00
Greyson Parrelli 837230d72d Bump version to 4.61.0 2020-05-29 19:18:55 -04:00
Greyson Parrelli f544ec4126 Updated language translations. 2020-05-29 19:18:02 -04:00
Greyson Parrelli 79dbf85c1e Improve local encrypted PIN storage. 2020-05-29 19:15:56 -04:00
Greyson Parrelli 61fe6cc961 Enable the ability to react with any emoji. 2020-05-29 19:14:37 -04:00
Greyson Parrelli 70c88b68e2 Store recent reactions separately from keyboard emoji. 2020-05-29 19:14:37 -04:00
Greyson Parrelli d70c33d20f Add support for mark as unread. 2020-05-29 19:14:37 -04:00
Greyson Parrelli 6b2e000e61 Prevent waiting for old queues in our retrieval strategies. 2020-05-29 19:14:37 -04:00
Alan Evans b9f11dafff New internal testing flag and V1 group creation button. All menus create GV1. 2020-05-29 19:14:37 -04:00
Alan Evans 9b32eaeb8a Do not log URLs. 2020-05-29 19:14:37 -04:00
Alan Evans a99c0d438e Rename GV2 "version" to "revision". 2020-05-29 19:14:37 -04:00
Alex Hart c634c24afb Utilize Wrapper instead of dynamic theme. 2020-05-29 19:14:37 -04:00
Alex Hart 2ddd1437cf Utilize exclusive AudioFocus. 2020-05-29 19:14:37 -04:00
Alan Evans 9da309ca48 Enforce a local GV2 capacity limit driven by a feature flag. 2020-05-29 19:14:37 -04:00
henry cfcd451db7 Fix crash on unlink device when offline. 2020-05-29 09:51:21 -04:00
Alex Hart 5ab72fd1a9 Ask for permission before launching avatar sheet. 2020-05-29 09:51:21 -04:00
Alan Evans daace9bd1a Audio wave forms on voice notes. 2020-05-29 09:51:21 -04:00
Alan Evans 69adcd1d69 Tap avatar in chat preferences or group management to see full screen. 2020-05-29 09:51:21 -04:00
Alex Hart 0711a22188 Add overflow toast and fix edit menu option. 2020-05-29 09:51:21 -04:00
Greyson Parrelli 3a06412cd8 Throttle notifications when doing the intial message fetch. 2020-05-29 09:51:21 -04:00
Alan Evans 51c82702e2 Remove expectation of ActionBar in DeviceProvisioningActivity.
Fixes #9661
2020-05-29 09:51:21 -04:00
Greyson Parrelli 1b01196ec6 Refactor ThreadRecord. 2020-05-29 09:51:21 -04:00
Greyson Parrelli 1cd6b58ece Don't enqueue duplicate PushDecryptMessageJobs. 2020-05-29 09:51:21 -04:00
Greyson Parrelli ea8e13b1c8 Create a WebsocketDrainedConstraint. 2020-05-29 09:51:21 -04:00
Greyson Parrelli f392229393 Extract MessageNotifier interface. 2020-05-29 09:51:21 -04:00
Greyson Parrelli a299bafe89 Create a new system for fetching the intial batch of messages. 2020-05-29 09:51:21 -04:00
Alex Hart d2bf539504 Clear sticky WebRtcViewModel events when initiating a new call. 2020-05-29 09:51:21 -04:00
Alex Hart 903c3989b9 Fix chip jank and other groups v2 ux issues. 2020-05-29 09:51:21 -04:00
Alan Evans 00996f0d7a Rename back to build.gradle 2020-05-29 09:51:21 -04:00
Alan Evans 4aded3a436 Close keyboard on contact list scroll. 2020-05-29 09:51:20 -04:00
Alan Evans 9acdc37729 Alphabetical member order. 2020-05-29 09:51:20 -04:00
Greyson Parrelli d4cdcbe54f Improve logging around group sends. 2020-05-29 09:51:20 -04:00
Alex Hart 6fa2a0f411 Polish UX for groups v2 management. 2020-05-29 09:51:20 -04:00
Alex Hart 558a8e4a14 Add polish to groups v2 creation flow. 2020-05-29 09:51:20 -04:00
Alan Evans 8947b82034 Make GV2 feature flags remote capable. 2020-05-29 09:51:20 -04:00
Alan Evans 56551025e9 Detect if group v2 is active from membership. 2020-05-29 09:51:20 -04:00
Alan Evans befb4939d5 Restore groups from storage service. 2020-05-29 09:51:20 -04:00
Alan Evans 289f7aba63 Add versioned profiles feature flag. 2020-05-29 09:51:20 -04:00
Alan Evans 28bd245b96 While testing GV2 without UUID, fail jobs that hit UuidRecipientError. 2020-05-29 09:51:20 -04:00
Alan Evans c5e7300df2 Fix matches logic in contact selection. 2020-05-29 09:51:20 -04:00
Greyson Parrelli fe25d941bb Prevent FCM bottlenecking. 2020-05-29 09:51:20 -04:00
Alan Evans 4cda267f3b Show pending count and allow view of zero pending screen. 2020-05-29 09:51:20 -04:00
Alex Hart 82ba7e2b8b Display "You" at end of members list in ConversationTitleView. 2020-05-29 09:51:20 -04:00
Alex Hart 41ebaf3938 Clean up Overflow menu for GV2 groups. 2020-05-29 09:51:20 -04:00
Alex Hart 090c400037 Collapse title into toolbar on scroll in ManageGroupFragment. 2020-05-29 09:51:20 -04:00
Alan Evans 12b1232ac0 Fix groups v2 patch response handler. 2020-05-29 09:51:20 -04:00
Alex Hart 204a84c522 Apply proper spacing to RecipientBottomSheetDialogFragment. 2020-05-29 09:51:20 -04:00
Alan Evans 526afd539b Fix avatar tap in conversation multi-select mode. 2020-05-29 09:51:20 -04:00
Greyson Parrelli d708984abd Require users be a system contact or whitelisted to appear in the contact list. 2020-05-29 09:51:20 -04:00
Greyson Parrelli 9d39db6428 Add additional account restore logging, prevent double avatar fetch. 2020-05-29 09:51:20 -04:00
Alan Evans 67a8ec0d39 Only admin can cancel any invite. 2020-05-29 09:51:20 -04:00
Alan Evans 297a7d0ef8 Handle absent change during invite. 2020-05-29 09:51:20 -04:00
Bastian Köcher 4712833853 Always convert HEIC images to JPEG.
This pr changes the behavior of sending HEIC images to always convert
them to JPEG. This conversion is required to support image inline
viewing accross different devices and operating systems. This follows
the same strategy as on IOS: https://github.com/signalapp/Signal-iOS/pull/2511

Fixes: https://github.com/signalapp/Signal-iOS/issues/4374 & https://github.com/signalapp/Signal-Android/issues/9395
2020-05-29 09:51:20 -04:00
Alan Evans 11d17f7496 GV2 storage service syncing. 2020-05-29 09:51:20 -04:00
Alan Evans 36df3f234f Enable the Zk group library. 2020-05-29 09:51:20 -04:00
Greyson Parrelli 098b298646 Add a network constraint to RemoteConfigRefreshJob. 2020-05-29 09:51:20 -04:00
Alan Evans 2f9320989a Server signed group v2 changes sent and received P2P. 2020-05-29 09:51:20 -04:00
Alan Evans ec8d5defd4 Protect against unknown GV2 UUIDs. 2020-05-29 09:51:20 -04:00
Greyson Parrelli 981676c7f8 Bump version to 4.60.9 2020-05-29 09:40:26 -04:00
Greyson Parrelli 7c5ae57784 Updated language translations. 2020-05-29 09:38:57 -04:00
Alex Hart fc7be87468 Downgrade AudioManagerCompat errors to warnings. 2020-05-29 10:31:36 -03:00
Greyson Parrelli e55d8007fc Bump version to 4.60.8 2020-05-28 18:34:06 -04:00
Greyson Parrelli 43b7aa2d52 Updated language translations. 2020-05-28 18:33:46 -04:00
Alex Hart cd1bad0718 Fix bluetooth behavior. 2020-05-28 17:36:40 -03:00
Greyson Parrelli 6b47618351 Bump version to 4.60.7 2020-05-26 18:27:05 -04:00
Greyson Parrelli b6d384120d Updated language translations. 2020-05-26 18:26:39 -04:00
Greyson Parrelli 1268b26c1f Auto-dismiss PIN reminder dialog as you type. 2020-05-26 18:13:19 -04:00
Greyson Parrelli f1233bfddc Bump version to 4.60.6 2020-05-25 14:57:59 -04:00
Greyson Parrelli 1aa3e6afea Updated language translations. 2020-05-25 14:57:59 -04:00
Greyson Parrelli ce21eb241a Fix potential crash with data size in ConversationDataSource. 2020-05-25 14:57:59 -04:00
Greyson Parrelli f96fb72eb1 Don't show PIN reminders if you're not registered.
Fixes #9657
2020-05-25 13:14:38 -04:00
Greyson Parrelli 207c467c6b Don't insert identity verification message for the initial restore. 2020-05-24 13:00:16 -04:00
Alex Hart 9d1d9e33ed Bumped version to 4.60.5 2020-05-21 20:03:31 -03:00
Alex Hart e4a76c0690 Updated language translations. 2020-05-21 20:03:31 -03:00
Alex Hart 124c3e25e9 Implement layout changes to new call screen UX. 2020-05-21 20:03:31 -03:00
Greyson Parrelli 5cb1201903 Add the ability to disable PIN reminders. 2020-05-21 19:56:30 -03:00
Greyson Parrelli bb6ca80d5a Don't create identity change methods for brand new contacts. 2020-05-21 19:56:30 -03:00
Greyson Parrelli dc7c54a1f8 Ensure we upload the profile after a PIN restore. 2020-05-21 19:56:30 -03:00
Greyson Parrelli 23401440bf Prevent insertion of UUID-only contacts at the database level. 2020-05-21 19:56:30 -03:00
Greyson Parrelli f8f959e05a Make rate limit message more generic. 2020-05-20 14:22:33 -04:00
Alex Hart edbd4d2d03 Properly set profile key update flag. 2020-05-20 12:15:54 -03:00
Greyson Parrelli a0b4065be3 Fix potention OOB error when pulse-highlighting a message.
This basically happened if you used full-text search to search for the
latest message in a conversation, but when you navigated there, it
*also* had a header set (like a typing indicator or unknownSenderView).
2020-05-19 17:09:25 -04:00
Greyson Parrelli 1b2f964f32 Fix possible crash around loading initial conversation pages. 2020-05-19 16:20:20 -04:00
Alex Hart eaf5280d99 Bumped version to 4.60.4 2020-05-19 16:51:33 -03:00
Alex Hart d435da980f Updated language translations. 2020-05-19 16:51:33 -03:00
Greyson Parrelli 8d3a91f3a4 Fix possible data source invalidation loop. 2020-05-19 16:51:33 -03:00
Greyson Parrelli b80c339c5a Fix an issue where the add profile prompt wasn't dismissed. 2020-05-19 16:51:33 -03:00
Alan Evans 34159fc9da Log successful pin setting. 2020-05-19 16:34:52 -03:00
Alex Hart b509ee9ee0 Bumped version to 4.60.3 2020-05-18 17:03:45 -03:00
Alex Hart a6819448b9 fixup! Consolidate Call UI visibility selection logic. 2020-05-18 16:43:30 -03:00
Alex Hart f2847f9aa5 Bumped version to 4.60.2 2020-05-18 16:31:20 -03:00
Alex Hart 8f01e5e1c3 Updated language translations. 2020-05-18 16:31:20 -03:00
Alan Evans acb2f43620 Make Manage Group menu item replace Edit Group for GV2. 2020-05-18 16:31:20 -03:00
Greyson Parrelli 62ac65e4d8 Improve paging performance on slower devices. 2020-05-18 16:31:20 -03:00
Alex Hart 8f183bdcdc Consolidate Call UI visibility selection logic. 2020-05-18 16:31:20 -03:00
Greyson Parrelli 3d135d155e Disable view prefetching for now. 2020-05-18 16:31:20 -03:00
Alan Evans 090c811391 Force app compat version 1.1.0-beta01. 2020-05-18 16:31:20 -03:00
Alex Hart 2a9e8dc525 Bumped version to 4.60.1 2020-05-15 19:02:18 -03:00
Alex Hart cb0b22cf2c Updated language translations. 2020-05-15 19:02:18 -03:00
Alex Hart 5aba3517ce Upgrade to RingRTC 2.0.3 and implement rounded corners for local pip. 2020-05-15 19:02:18 -03:00
Alex Hart 726f665388 Upgrade AppCompat to 1.2.0-rc01. 2020-05-15 19:02:18 -03:00
Alex Hart e2ac55e9ac Fix ellapsed call timer restarting between activity restarts. 2020-05-15 19:02:18 -03:00
Greyson Parrelli fa5729bac6 Better handle identity key changes in response to storage service syncs. 2020-05-15 19:02:18 -03:00
Greyson Parrelli e714cb6423 Fix potential issues with ConversationDataSource boundaries. 2020-05-15 19:02:18 -03:00
Alex Hart 35a0162d5c Utilize EmojiTextView instead of TextView. 2020-05-15 19:02:18 -03:00
Alex Hart 76740adc3f Fix controls are removed when remote video is disabled. 2020-05-15 13:05:00 -03:00
Alex Hart 1c814141a2 Fix NullPointerException when trying to launch InviteActivity. 2020-05-15 10:43:25 -03:00
Alan Evans 5545daf992 Live group membership count in conversation. 2020-05-15 10:28:48 -03:00
Alan Evans d300615d90 Ensure new group UI behind feature flag. 2020-05-15 10:27:39 -03:00
Alex Hart 908a5260c2 Enable note to self as recipient in share activity. 2020-05-15 10:03:49 -03:00
Alex Hart 7aac6644c3 Expand tappable area in header. 2020-05-14 16:27:52 -03:00
Alan Evans 3b673c07a0 Support gv2 avatar removal. 2020-05-14 15:57:40 -03:00
Alan Evans d726da822c Add network constraint to GV2 messages. 2020-05-14 15:23:15 -03:00
Alex Hart 7894f72b0f Enable speaker when initiating a video call. 2020-05-14 14:18:49 -03:00
Alan Evans 4c5822ac67 GV2 Update message description. 2020-05-14 13:59:34 -03:00
Alex Hart b917cccbee Bumped version to 4.60.0 2020-05-14 11:22:28 -03:00
Alex Hart 01d2d05d8e Updated language translations. 2020-05-14 11:22:28 -03:00
Alan Evans 4de86cb6cf Prevent ZkGroup link crashes. 2020-05-14 11:22:28 -03:00
henry 8861ad76ed Fix start SubmitDebugLog from registration and passphrase prompt. 2020-05-14 11:22:28 -03:00
Alan Evans ef86372635 Ensure that the unknown UUID does not create an entry. 2020-05-14 11:22:28 -03:00
Alex Hart ccff7b1148 Implement new group creation screens behind flag. 2020-05-14 11:22:28 -03:00
Greyson Parrelli ed0825112d Fix some ordering problems with conversation data loading. 2020-05-14 11:22:28 -03:00
Alan Evans b8df90531f GV2 message contexts. 2020-05-14 11:22:28 -03:00
Greyson Parrelli f099c3591c Run PushProcessMessageJobs in parallel. 2020-05-14 11:22:28 -03:00
Greyson Parrelli ed33e048ad Add CachedLayoutInflater to improve conversation render performance. 2020-05-14 11:22:28 -03:00
Greyson Parrelli 7fd3bfa30c Revert "Check to see if FCM is available at app launch."
This reverts commit eea7174f1d.
2020-05-14 11:22:28 -03:00
Alex Hart 07a492a32c Add dot character to reactions bottom sheet all tab label. 2020-05-14 11:22:28 -03:00
Alan Evans 11fffbd79e Remove P2P group change sending. 2020-05-14 11:22:28 -03:00
Alan Evans eff564ad88 Adapt message requests to support invite flow. 2020-05-14 11:22:28 -03:00
Greyson Parrelli d3d53e6099 Reduce recipient dirty state logging verbosity. 2020-05-14 11:22:28 -03:00
Greyson Parrelli 53d122ed55 Fix jumping to last seen position. 2020-05-14 11:22:28 -03:00
Alan Evans 1778c1ef7d Prevent some IOExceptions when past the end of stream. 2020-05-14 11:22:28 -03:00
Alan Evans a510bc74e6 Recipient Id cache. 2020-05-14 11:22:28 -03:00
Alan Evans a9ecdbdfec Groups V2 capability set by the feature flag. 2020-05-14 11:22:28 -03:00
Alan Evans 06ab3cf013 Fix cases of inlined & missing log tags. 2020-05-14 11:22:28 -03:00
Alan Evans 3db5da1c8d Generalize media input for use with Audio. 2020-05-14 11:22:28 -03:00
Greyson Parrelli 5937a50b6d Fix message receive timestamps on media messages. 2020-05-14 11:22:28 -03:00
Alan Evans b4191ee5cc Fix usages of service logging in app. 2020-05-14 11:22:28 -03:00
Alan Evans c63e42715e New logging lint checks.
[LogNotAppSignal] tells you about using signal service logger in the app.
[LogTagInlined] tells you about not using a constant tag.
2020-05-14 11:22:28 -03:00
Alex Hart 26e582d806 Integrate RingRTC v2.0.1 2020-05-14 11:22:28 -03:00
Alan Evans ee9270845a Create GV2 group behind feature flag. 2020-05-14 11:22:28 -03:00
Alan Evans 6cf33897c0 Remove superfluous groups v2 capability checks. 2020-05-14 11:22:28 -03:00
Freddy Tuxworth 2161bbb8fa Display "No matching countries" when no filter matches found.
Fixes #9518
2020-05-14 11:22:28 -03:00
Greyson Parrelli b75088874e Migrate conversation rendering to the paging library. 2020-05-14 11:22:28 -03:00
Alan Evans 9ac1897880 Job changes for GroupsV2 message receive and profile key updates. 2020-05-14 11:22:28 -03:00
Alan Evans 36c43ed2fa Ensure latest V2 group state from server upon conversation open. 2020-05-14 11:22:28 -03:00
Alan Evans 8084822f16 Connect GV2 title and avatar updates and prevent no-change avatar updates. 2020-05-14 11:22:28 -03:00
Alan Evans 959718618f Deprecate some ViewUtil methods. Inline others. Remove some old API code. 2020-05-14 11:22:28 -03:00
Alan Evans 75f3fe0cec Correct access control for MMS groups. 2020-05-14 11:22:28 -03:00
Alan Evans b800477365 GV2 leave and eject operations. 2020-05-14 11:22:28 -03:00
Alex Hart b191341c57 Add some polish to the groups V2 manager UI. 2020-05-14 11:22:28 -03:00
leet 88a40be901 Fix backup timestamp language.
Fixes #8842
Fixes #8986
2020-05-14 11:22:28 -03:00
Greyson Parrelli 3fef58057e Add additional info to support emails and debuglogs. 2020-05-14 11:22:28 -03:00
Greyson Parrelli b156e4a79a Always use the UD cert with a UUID. 2020-05-14 11:22:28 -03:00
Alan Evans 30ac264cd3 Rename Group update message classes. 2020-05-14 11:22:28 -03:00
Alan Evans a9b00e1cd3 Remove instances of Android logging. 2020-05-14 11:22:28 -03:00
Alex Hart d94fc4bc13 Implement ability to react with any emoji behind a flag. 2020-05-14 11:22:28 -03:00
Greyson Parrelli 40b5339ef8 Allow auto-download for users you've shared your profile with. 2020-05-14 11:22:28 -03:00
Alan Evans 86f0456e8c Group Manager V2 operations. 2020-05-14 11:22:28 -03:00
Alan Evans 48a693793f GV2 Group Manager. 2020-05-14 11:22:28 -03:00
Alan Evans ff28d72db6 New GV2 internal prefix and scrubber. 2020-05-13 16:18:18 -04:00
Alan Evans 456857bbbd Add custom lint rule project. 2020-05-13 16:18:18 -04:00
Alan Evans 7f17b66a6c Upgrade gradle and gradle plugin. 2020-05-13 16:18:18 -04:00
Greyson Parrelli 310ec8f296 Remove CellServiceConstraint in favor of NetworkOrCellServiceConstraint.
If a job was enqueued with a CellServiceConstraint (which is currently
only SMS jobs), then it'll never run until it gets service, even if you
flip the "enable SMS sending over wifi" toggle.

This has created bad situations in the past, where SMS jobs just get
stuck on devices that never report having cell service (like VM's or
wifi only devices).

This fixes it by *always* using NetworkOrCellServiceConstraint, and then
deciding whether a constraint is met by checking the "wifi SMS" setting
at decision-time.
2020-05-13 16:18:18 -04:00
Alan Evans 0c2afa9438 Fix FCM token via phone call registration.
Fixes #8992
2020-05-13 16:18:18 -04:00
Alex Hart c3832cf8b1 New group notifications management ui. 2020-05-13 16:18:18 -04:00
Greyson Parrelli a2de8a2a05 Ensure you can't set null values in DefaultValueLiveData. 2020-05-13 16:18:18 -04:00
Greyson Parrelli 3b601896d2 Fix crash in SubmitDebugLogActivity. 2020-05-13 16:18:18 -04:00
Greyson Parrelli e1a90bcb00 Transition conversation loading from a Loader to a Repository. 2020-05-13 16:18:18 -04:00
Greyson Parrelli 2b65916344 Show calling foreground notification on all OS versions.
Fixes #9516
Fixes #9414
2020-05-13 16:18:18 -04:00
Greyson Parrelli f149005026 Add support for remote config v1.1 2020-05-13 16:18:18 -04:00
Alex Hart 5eb663aa1b New group avatar and name selection screen. 2020-05-13 16:18:18 -04:00
Alan Evans 12b7d6c0e3 Use bottom sheet shape. 2020-05-13 16:18:18 -04:00
Alan Evans 723639d928 New group management screen. 2020-05-13 16:18:18 -04:00
Greyson Parrelli e0502c24e1 Only search for visible parts of a contact. 2020-05-13 16:18:18 -04:00
Alex Hart 358d6333c3 Open new recipient bottom sheet when accessing contact from group context. 2020-05-13 16:18:18 -04:00
Alan Evans 0b279d1df3 Group contact chips behind feature flag. 2020-05-13 16:18:18 -04:00
Alan Evans 8e0fba7992 New group button behind new Group UI feature flag. 2020-05-13 16:18:18 -04:00
Alex Hart d5419ec9fa Implement new call screen UI/UX. 2020-05-13 16:18:18 -04:00
Alan Evans 33e3f78be6 LiveDataUtil combineLatest. 2020-05-13 16:17:29 -04:00
Alex Hart 3c5ad519dd Decrease QuoteView reveal animation duration to 150ms. 2020-05-13 16:17:29 -04:00
Alan Evans 17c5b858b5 Recipient bottom sheet. 2020-05-13 16:17:29 -04:00
Greyson Parrelli f6f6496c9c Bump version to 4.59.10 2020-05-13 15:40:44 -04:00
Greyson Parrelli b1d725e23a Updated language translations. 2020-05-13 15:40:44 -04:00
Greyson Parrelli a74622997e Bump libsignal-metadata to 0.1.2
Includes fix for how we're prioritizing UUID vs E164.

Fixes #9621
2020-05-13 15:40:42 -04:00
Greyson Parrelli b1a200001e Bump version to 4.59.9 2020-05-09 13:19:57 -04:00
Greyson Parrelli 3b1041fa1f Updated language translations. 2020-05-09 13:19:31 -04:00
Greyson Parrelli a83ccc18bb Fix processing of early messages.
1. Eliminated any possibility of infinite recursion.
2. Handle the fact that you can have multiple 'early contents' for a
   single message.
2020-05-09 13:16:45 -04:00
Greyson Parrelli 618b1b5ace Handle PIN creation failure better. 2020-05-09 13:16:45 -04:00
Greyson Parrelli 14858adc88 Bump version to 4.59.8 2020-05-04 18:22:45 -04:00
Greyson Parrelli c07f35f3aa Updated language translations. 2020-05-04 18:21:50 -04:00
Alan Evans 87eab27996 Prevent the creation of 'weak' PINs.
Simple checks to prevent the same number, or sequentially
increasing/decreasing PINs. e.g. 1111, 1234, 54321, etc.
2020-05-04 18:17:36 -04:00
Greyson Parrelli b7296a4fe3 Bump version to 4.59.7 2020-05-04 11:06:28 -04:00
Greyson Parrelli 3fb9ae1fb4 Updated language translations. 2020-05-04 11:05:55 -04:00
Greyson Parrelli 9705939489 Fix issue with editing and forwarding a received video. 2020-05-04 10:54:55 -04:00
Greyson Parrelli eca67b1204 Broaden exception handling in custom DNS.
A set of LG devices is crashing when using the custom DNS. Safest thing
for now would be to treat all failures as network errors while we we try
to get a repro to figure out what's happening.
2020-05-04 10:54:55 -04:00
Greyson Parrelli c59fc3581a Make LiveRecipientCache throw exceptions instead of errors.
Errors were causing crash loops if they occur in a job. This will still
allow the app to crash, but prevent loops.
2020-05-04 00:48:09 -04:00
Greyson Parrelli e00f8c94ff Bumped version to 4.59.6 2020-04-30 17:03:28 -04:00
Greyson Parrelli 4186153f0c Updated language translations. 2020-04-30 17:03:28 -04:00
Greyson Parrelli 6c01807f4f Fix issue with PIN verification. 2020-04-30 17:03:28 -04:00
Greyson Parrelli 9d35fb397b Fix issue with re-using forwarded attachment pointers.
We were deleting upload data for incoming attachments when we shouldn't
have.

Fixes #9570
2020-04-30 16:36:06 -04:00
Jim Gustafson c9f2f57427 Update to ringrtc v1.3.2 2020-04-30 08:12:31 -07:00
4220 changed files with 317869 additions and 78885 deletions
+4
View File
@@ -0,0 +1,4 @@
root = true
[*.kt]
indent_size = 2
+1
View File
@@ -0,0 +1 @@
custom: https://signal.org/donate/
-45
View File
@@ -1,45 +0,0 @@
<!-- 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.
Before we begin, please note that this tracker is only for issues. It is not for questions, comments, or feature requests.
If you would like to discuss a new feature or submit suggestions, please visit the community forum:
https://community.signalusers.org
If you are looking for support, please visit our support center:
https://support.signal.org/
or email support@signal.org
Let's begin with a checklist: Replace the empty checkboxes [ ] below with checked ones [x] accordingly. -->
- [ ] I have searched open and closed issues for duplicates
- [ ] I am submitting a bug report for existing functionality that does not work as intended
- [ ] I have read https://github.com/signalapp/Signal-Android/wiki/Submitting-useful-bug-reports
- [ ] This isn't a feature request or a discussion topic
----------------------------------------
### Bug description
Describe here the issue that you are experiencing.
### Steps to reproduce
- using hyphens as bullet points
- list the steps
- that reproduce the bug
**Actual result:** Describe here what happens after you run the steps above (i.e. the buggy behaviour)
**Expected result:** Describe here what should happen after you run the steps above (i.e. what would be the correct behaviour)
### Screenshots
<!-- you can drag and drop images below -->
### Device info
<!-- replace the examples with your info -->
**Device:** Manufacturer Model XVI
**Android version:** 0.0.0
**Signal version:** 0.0.0
### Link to debug log
<!-- immediately after the bug has happened capture a debug log via Signal's advanced settings and paste the link below -->
+54
View File
@@ -0,0 +1,54 @@
---
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.
Before we begin, please note that this tracker is only for issues. It is not for questions, comments, or feature requests.
If you would like to discuss a new feature or submit suggestions, please visit the community forum:
https://community.signalusers.org
If you are looking for support, please visit our support center:
https://support.signal.org/
or email support@signal.org
Let's begin with a checklist: Replace the empty checkboxes [ ] below with checked ones [x] accordingly. -->
- [ ] I have searched open and closed issues for duplicates
- [ ] I am submitting a bug report for existing functionality that does not work as intended
- [ ] I have read https://github.com/signalapp/Signal-Android/wiki/Submitting-useful-bug-reports
- [ ] This isn't a feature request or a discussion topic
----------------------------------------
### Bug description
Describe here the issue that you are experiencing.
### Steps to reproduce
- using hyphens as bullet points
- list the steps
- that reproduce the bug
**Actual result:** Describe here what happens after you run the steps above (i.e. the buggy behaviour)
**Expected result:** Describe here what should happen after you run the steps above (i.e. what would be the correct behaviour)
### Screenshots
<!-- you can drag and drop images below -->
### Device info
<!-- replace the examples with your info -->
**Device:** Manufacturer Model XVI
**Android version:** 0.0.0
**Signal version:** 0.0.0
### Link to debug log
<!-- immediately after the bug has happened capture a debug log via Signal's advanced settings and paste the link below -->
+20
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.
+15 -1
View File
@@ -6,6 +6,7 @@ on:
branches: branches:
- 'master' - 'master'
- '4.**' - '4.**'
- '5.**'
jobs: jobs:
build: build:
@@ -13,12 +14,25 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v2
- name: set up JDK 1.8 - name: set up JDK 1.8
uses: actions/setup-java@v1 uses: actions/setup-java@v1
with: with:
java-version: 1.8 java-version: 1.8
- name: Validate Gradle Wrapper - name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1 uses: gradle/wrapper-validation-action@v1
- name: Remove Android S
run: $ANDROID_HOME/tools/bin/sdkmanager --uninstall "platforms;android-S"
- name: Build with Gradle - name: Build with Gradle
run: ./gradlew qa run: ./gradlew qa
- name: Archive reports for failed build
if: ${{ failure() }}
uses: actions/upload-artifact@v2
with:
name: reports
path: '*/build/reports'
+18
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
+3 -1
View File
@@ -1,6 +1,8 @@
.classpath .classpath
captures/ captures/
project.properties project.properties
keystore.debug.properties
keystore.staging.properties
.project .project
.settings .settings
bin/ bin/
@@ -23,5 +25,5 @@ ffpr
test/androidTestEspresso/res/values/arrays.xml test/androidTestEspresso/res/values/arrays.xml
obj/ obj/
jni/libspeex/.deps/ jni/libspeex/.deps/
*.sh
pkcs11.password pkcs11.password
dev.keystore
+193
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
View File
@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>
+1 -1
View File
@@ -83,7 +83,7 @@ There are several other ways to get involved:
* Try to reproduce issues and help with troubleshooting. * Try to reproduce issues and help with troubleshooting.
* Discover solutions to open issues and post any relevant findings. * Discover solutions to open issues and post any relevant findings.
* Test other people's pull requests. * Test other people's pull requests.
* Contribute to Signal via the [Freedom of the Press Foundation's donation page](https://freedom.press/crowdfunding/signal/). * [Donate to Signal.](https://signal.org/donate/)
* Share Signal with your friends and family. * Share Signal with your friends and family.
Signal is made for you. Thank you for your feedback and support. Signal is made for you. Thank you for your feedback and support.
-25
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}
+1 -3
View File
@@ -59,9 +59,7 @@ The form and manner of this distribution makes it eligible for export under the
## License ## License
Copyright 2011 Whisper Systems Copyright 2013-2020 Signal
Copyright 2013-2020 Open Whisper Systems
Licensed under the GPLv3: http://www.gnu.org/licenses/gpl-3.0.html Licensed under the GPLv3: http://www.gnu.org/licenses/gpl-3.0.html
-287
View File
@@ -1,287 +0,0 @@
# Reproducible Builds
## TL;DR
You can just use these [instructions](https://signal.org/blog/reproducible-android/) from the official announcement at Open Whisper Systems's blog:
```
# Clone the Signal Android source repository
$ git clone https://github.com/signalapp/Signal-Android.git && cd Signal-Android
# Check out the release tag for the version you'd like to compare
$ git checkout v[the version number]
# Build using the Docker environment
$ docker run --rm -v $(pwd):/project -w /project whispersystems/signal-android:1.3 ./gradlew clean assembleRelease
# Verify the APKs
$ python3 apkdiff/apkdiff.py build/outputs/apks/project-release-unsigned.apk path/to/SignalFromPlay.apk
```
Note that the instructions above use a pre-built Signal Docker image from [Docker Hub](https://hub.docker.com/u/whispersystems/). If you wish to compile the image yourself, continue reading the longer version below.
***
## Introduction
Since version 3.15.0 Signal for Android has supported reproducible builds. This is achieved by replicating the build environment as a Docker image. You'll need to build the image, run a container instance of it, compile Signal inside the container and finally compare the resulted APK to the APK that is distributed in the Google Play Store.
The command line parts in this guide are written for Linux but with some little modifications you can adapt them to macOS (OS X) and Windows. In the following sections we will use `3.15.2` as an example Signal version. You'll just need to replace all occurrences of `3.15.2` with the version number you are about to verify.
## Setting up directories
First let's create a new directory for this whole reproducible builds project. In your home folder (`~`), create a new directory called `reproducible-signal`.
```
user@host:$ mkdir ~/reproducible-signal
```
Next create another directory inside `reproducible-signal` called `apk-from-google-play-store`.
```
user@host:$ mkdir ~/reproducible-signal/apk-from-google-play-store
```
We will use this directory to share APKs between the host OS and the Docker container.
Finally create one more directory inside `reproducible-signal` called `image-build-context`.
```
user@host:$ mkdir ~/reproducible-signal/image-build-context
```
This directory will be used later to build our Docker image.
## Getting the Google Play Store version of Signal APK
To compare the APKs we of course need a version of Signal from the Google Play Store.
First make sure that the Signal version you want to verify is installed on your Android device. You'll need `adb` for this part.
Plug your device to your computer and run this command to pull the APK from the device:
```
user@host:$ adb pull $(adb shell pm path org.thoughtcrime.securesms | grep /base.apk | awk -F':' '{print $2}') ~/reproducible-signal/apk-from-google-play-store/Signal-$(adb shell dumpsys package org.thoughtcrime.securesms | grep versionName | awk -F'=' '{print $2}').apk
```
This will pull a file into `~/reproducible-signal/apk-from-google-play-store/` with the name `Signal-<version>.apk`
Alternatively, you can do this step-by-step:
```
user@host:$ adb shell pm path org.thoughtcrime.securesms
```
This will output something like:
```
package:/data/app/org.thoughtcrime.securesms-aWRzcGlzcG9wZA==/base.apk
```
The output will tell you where the Signal APK is located in your device. (In this example the path is `/data/app/org.thoughtcrime.securesms-aWRzcGlzcG9wZA==/base.apk`)
Now using this information, pull the APK from your device to the `reproducible-signal/apk-from-google-play-store` directory you created before:
```
user@host:$ adb pull \
/data/app/org.thoughtcrime.securesms-aWRzcGlzcG9wZA==/base.apk \
~/reproducible-signal/apk-from-google-play-store/Signal-3.15.2.apk
```
We will use this APK in the final part when we compare it with the self-built APK from GitHub.
## Identifying the ABI
Since v4.37.0, the APKs have been split by ABI, the CPU architecture of the target device. Google play will serve the correct one to you for your device.
To identify which ABIs the google play APK supports, we can look inside the APK, which is just a zip file:
```
user@host:$ unzip -l ~/reproducible-signal/apk-from-google-play-store/Signal-*.apk | grep lib/
```
Example:
```
1214348 00-00-1980 00:00 lib/armeabi-v7a/libconscrypt_jni.so
151980 00-00-1980 00:00 lib/armeabi-v7a/libcurve25519.so
4164320 00-00-1980 00:00 lib/armeabi-v7a/libjingle_peerconnection_so.so
13948 00-00-1980 00:00 lib/armeabi-v7a/libnative-utils.so
2357812 00-00-1980 00:00 lib/armeabi-v7a/libsqlcipher.so
```
As there is just one sub directory of `lib/` called `armeabi-v7a`, that is your ABI. Make a note of that for later. If you see more than one subdirectory of `lib/`:
```
1214348 00-00-1980 00:00 lib/armeabi-v7a/libconscrypt_jni.so
151980 00-00-1980 00:00 lib/armeabi-v7a/libcurve25519.so
4164320 00-00-1980 00:00 lib/armeabi-v7a/libjingle_peerconnection_so.so
13948 00-00-1980 00:00 lib/armeabi-v7a/libnative-utils.so
2357812 00-00-1980 00:00 lib/armeabi-v7a/libsqlcipher.so
2111376 00-00-1980 00:00 lib/x86/libconscrypt_jni.so
201056 00-00-1980 00:00 lib/x86/libcurve25519.so
7303888 00-00-1980 00:00 lib/x86/libjingle_peerconnection_so.so
5596 00-00-1980 00:00 lib/x86/libnative-utils.so
3977636 00-00-1980 00:00 lib/x86/libsqlcipher.so
```
Then that means you have the `universal` APK.
## Installing Docker
Install Docker by following the instructions for your platform at https://docs.docker.com/engine/installation/
Your platform might also have its own preferred way of installing Docker. E.g. Ubuntu has its own Docker package (`docker.io`) if you do not want to follow Docker's instructions.
In the following sections we will assume that your Docker installation works without issues. So after installing, please make sure that everything is running smoothly before continuing.
## Building a Docker image for Signal
#### Grabbing the `Dockerfile`
First you will need the `Dockerfile` for Signal Android. It comes bundled with Signal's source code. The `Dockerfile` contains instructions on how to automatically build a Docker image for Signal. You just need to run it and it builds itself.
Download the `Dockerfile` to the `image-build-context` directory.
```
user@host:$ wget -O ~/reproducible-signal/image-build-context/Dockerfile_v3.15.2 \
https://raw.githubusercontent.com/signalapp/Signal-Android/v3.15.2/Dockerfile
```
Note that the `Dockerfile` is specific to the Signal version you want to compare to. Again you have to adjust the URL above to match the right version. (Though sometimes the file might not be up to date, see the [Troubleshooting section](#troubleshooting))
#### Building the image
Now we have everything we need to build the Docker image for Signal. Go to the `image-build-context` directory:
```
user@host:$ cd ~/reproducible-signal/image-build-context
```
And list the contents.
```
user@host:$ ls
```
The output should look like this:
```
Dockerfile_v3.15.2
```
Now in this directory build the image using `Dockerfile_v3.15.2`:
```
user@host:$ docker build --file Dockerfile_v3.15.2 --tag signal-android .
```
(Note that there is a dot at the end of that command!)
Wait a few years for the build to finish... :construction_worker:
(Depending on your computer and network connection, this may take several minutes.)
:calendar: :sleeping:
After the build has finished, you may wish to list all your Docker images to see that it's really there:
```
user@host:$ docker images
```
Output should look something like this:
```
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
signal-android latest c6b84450b896 46 seconds ago 2.94 GB
ubuntu 14.04.3 8693db7e8a00 9 weeks ago 187.9 MB
```
## Compiling Signal inside a container
Next we will run a container of the image we just built, grab Signal's source code and compile Signal.
First go to the `reproducible-signal` directory:
```
user@host:$ cd ~/reproducible-signal/
```
To run a new ephemeral container with an interactive terminal session execute the following long command:
```
user@host:$ docker run \
--name signal \
--rm \
--interactive \
--tty \
--volume $(pwd)/apk-from-google-play-store:/signal-build/apk-from-google-play-store \
--workdir /signal-build \
signal-android
```
Now you are inside the container.
Grab Signal's source code from GitHub and go to the repository directory:
```
root@container:# git clone https://github.com/signalapp/Signal-Android.git
root@container:# cd Signal-Android
```
Before you can compile, you **must** ensure that you are at the right commit. In other words you **must** checkout the version you wish to verify (here we are verifying 3.15.2):
```
root@container:# git checkout --quiet v3.15.2
```
Now you may compile the release APK by running:
```
root@container:# ./gradlew clean assemblePlayRelease --exclude-task signProductionPlayRelease
```
This will take a few minutes :sleeping:
#### Checking if the APKs match
After the build has completed successfully we can finally compare if the APKs match. For the comparison we need of course the Google Play Store version of Signal APK which you copied to the `apk-from-google-play-store` directory in the beginning of this guide. Because we used that directory as a `--volume` parameter for our container, we can see all the files in that directory within our container.
So now we can compare the APKs using the `apkdiff.py` tool.
The above build step produced several APKs, one for each supported ABI and one universal one. You will need to determine the correct APK to compare.
Currently, the most common ABI is `armeabi-v7a`. Other options at this time include `x86` and `universal`. In the future it will also include 64-bit options, such as `x86_64` and `arm64-v8a`.
See [Identifying the ABI](#identifying-the-abi) above if you don't know the ABI of your play store APK.
Once you have determined the ABI, add an `abi` environment variable. For example, suppose we determine that `armeabi-v7a` is the ABI google play has served:
```
root@container:# export abi=armeabi-v7a
```
And the diff script to compare:
```
root@container:# python3 apkdiff/apkdiff.py \
build/outputs/apk/play/release/*play-$abi-release-unsigned*.apk \
../apk-from-google-play-store/Signal-3.15.2.apk
```
Output:
```
APKs match!
```
If you get `APKs match!`, you have successfully verified that the Google Play release matches with your own self-built version of Signal. Congratulations! Your APKs are a match made in heaven! :sparkles:
If you get `APKs don't match!`, you did something wrong in the previous steps. See the [Troubleshooting section](#troubleshooting) for more info.
## Comparing next time
If the build environment (i.e. `Dockerfile`) has not changed, you don't need to build the image again to verify a newer APK. You can just [run the container again](#compiling-signal-inside-a-container).
## Troubleshooting
If you cannot get things to work, please do not open an issue or comment on an existing issue at GitHub. Instead, ask for help at https://community.signalusers.org/c/development
Some common issues why things may not work:
- some pinned packages in the `Dockerfile` are not available anymore and building of the Docker image fails
- the Android packages in the Docker image are outdated and compiling Signal fails
- you built the Docker image with a wrong version of the `Dockerfile`
- you didn't checkout the correct Signal version tag with Git before compiling
- the ABI you selected is not the correct ABI, particularly if you see an error along the lines of `Sorted manifests don't match, lib/x86/libcurve25519.so vs lib/armeabi-v7a/libcurve25519.so`.
- this guide is outdated
- you are in a dream
- if you run into this issue: https://issuetracker.google.com/issues/110237303 try to add `resources.arsc` to the list of ignored files and compare again
+261 -111
View File
@@ -2,31 +2,17 @@ import org.signal.signing.ApkSignerUtil
import java.security.MessageDigest 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.5.1'
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: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'com.google.protobuf' apply plugin: 'com.google.protobuf'
apply plugin: 'androidx.navigation.safeargs' apply plugin: 'androidx.navigation.safeargs'
apply plugin: 'witness' apply plugin: 'witness'
apply plugin: 'org.jlleitschuh.gradle.ktlint'
apply from: 'translations.gradle' apply from: 'translations.gradle'
apply from: 'witness-verifications.gradle' apply from: 'witness-verifications.gradle'
apply plugin: 'org.jetbrains.kotlin.android'
apply plugin: 'app.cash.exhaustive'
repositories { repositories {
maven { maven {
@@ -35,24 +21,12 @@ repositories {
includeGroupByRegex "com\\.github\\.chrisbanes.*" includeGroupByRegex "com\\.github\\.chrisbanes.*"
} }
} }
maven {
url "https://raw.github.com/signalapp/maven/master/shortcutbadger/releases/"
content {
includeGroupByRegex "me\\.leolin.*"
}
}
maven { maven {
url "https://raw.github.com/signalapp/maven/master/circular-progress-button/releases/" url "https://raw.github.com/signalapp/maven/master/circular-progress-button/releases/"
content { content {
includeGroupByRegex "com\\.github\\.dmytrodanylyk\\.circular-progress-button\\.*" includeGroupByRegex "com\\.github\\.dmytrodanylyk\\.circular-progress-button\\.*"
} }
} }
maven {
url "https://raw.github.com/signalapp/maven/master/sqlcipher/release/"
content {
includeGroupByRegex "org\\.signal.*"
}
}
maven { // textdrawable maven { // textdrawable
url 'https://dl.bintray.com/amulyakhare/maven' url 'https://dl.bintray.com/amulyakhare/maven'
content { content {
@@ -63,6 +37,9 @@ repositories {
mavenCentral() mavenCentral()
jcenter() jcenter()
mavenLocal() mavenLocal()
maven {
url "https://dl.cloudsmith.io/qxAgwaeEE1vN8aLU/mobilecoin/mobilecoin/maven/"
}
} }
protobuf { protobuf {
@@ -80,38 +57,59 @@ protobuf {
} }
} }
def canonicalVersionCode = 625 def canonicalVersionCode = 871
def canonicalVersionName = "4.59.5" def canonicalVersionName = "5.15.4"
def postFixSize = 10 def postFixSize = 100
def abiPostFix = ['universal' : 0, def abiPostFix = ['universal' : 0,
'armeabi-v7a' : 1, 'armeabi-v7a' : 1,
'arm64-v8a' : 2, 'arm64-v8a' : 2,
'x86' : 3, 'x86' : 3,
'x86_64' : 4] 'x86_64' : 4]
def keystores = [ 'debug' : loadKeystoreProperties('keystore.debug.properties') ]
android { android {
flavorDimensions "none" buildToolsVersion BUILD_TOOL_VERSION
compileSdkVersion 28 compileSdkVersion COMPILE_SDK
buildToolsVersion '28.0.3'
flavorDimensions 'distribution', 'environment'
useLibrary 'org.apache.http.legacy' useLibrary 'org.apache.http.legacy'
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs = ["-Xallow-result-return-type"]
}
dexOptions { dexOptions {
javaMaxHeapSize "4g" 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 { defaultConfig {
versionCode canonicalVersionCode * postFixSize versionCode canonicalVersionCode * postFixSize
versionName canonicalVersionName versionName canonicalVersionName
minSdkVersion 19 minSdkVersion MINIMUM_SDK
targetSdkVersion 28 targetSdkVersion TARGET_SDK
multiDexEnabled true multiDexEnabled true
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
project.ext.set("archivesBaseName", "Signal"); project.ext.set("archivesBaseName", "Signal");
buildConfigField "long", "BUILD_TIMESTAMP", getLastCommitTimestamp() + "L" buildConfigField "long", "BUILD_TIMESTAMP", getLastCommitTimestamp() + "L"
buildConfigField "String", "GIT_HASH", "\"${getGitHash()}\""
buildConfigField "String", "SIGNAL_URL", "\"https://textsecure-service.whispersystems.org\"" buildConfigField "String", "SIGNAL_URL", "\"https://textsecure-service.whispersystems.org\""
buildConfigField "String", "STORAGE_URL", "\"https://storage.signal.org\"" buildConfigField "String", "STORAGE_URL", "\"https://storage.signal.org\""
buildConfigField "String", "SIGNAL_CDN_URL", "\"https://cdn.signal.org\"" buildConfigField "String", "SIGNAL_CDN_URL", "\"https://cdn.signal.org\""
@@ -119,16 +117,29 @@ android {
buildConfigField "String", "SIGNAL_CONTACT_DISCOVERY_URL", "\"https://api.directory.signal.org\"" buildConfigField "String", "SIGNAL_CONTACT_DISCOVERY_URL", "\"https://api.directory.signal.org\""
buildConfigField "String", "SIGNAL_SERVICE_STATUS_URL", "\"uptime.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_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 "String", "CONTENT_PROXY_HOST", "\"contentproxy.signal.org\""
buildConfigField "int", "CONTENT_PROXY_PORT", "443" buildConfigField "int", "CONTENT_PROXY_PORT", "443"
buildConfigField "String", "SIGNAL_AGENT", "\"OWA\"" buildConfigField "String", "SIGNAL_AGENT", "\"OWA\""
buildConfigField "String", "CDS_MRENCLAVE", "\"cd6cfc342937b23b1bdd3bbf9721aa5615ac9ff50a75c5527d441cd3276826c9\"" buildConfigField "String", "CDS_MRENCLAVE", "\"c98e00a4e3ff977a56afefe7362a27e4961e4f19e211febfbb19b897e6b80b15\""
buildConfigField "String", "KBS_ENCLAVE_NAME", "\"fe7c1bfae98f9b073d220366ea31163ee82f6d04bead774f71ca8e5c40847bfe\"" buildConfigField "KbsEnclave", "KBS_ENCLAVE", "new KbsEnclave(\"fe7c1bfae98f9b073d220366ea31163ee82f6d04bead774f71ca8e5c40847bfe\"," +
buildConfigField "String", "KBS_MRENCLAVE", "\"a3baab19ef6ce6f34ab9ebb25ba722725ae44a8872dc0ff08ad6d83a9489de87\"" "\"fe7c1bfae98f9b073d220366ea31163ee82f6d04bead774f71ca8e5c40847bfe\", " +
"\"a3baab19ef6ce6f34ab9ebb25ba722725ae44a8872dc0ff08ad6d83a9489de87\")";
buildConfigField "KbsEnclave[]", "KBS_FALLBACKS", "new KbsEnclave[0]"
buildConfigField "String", "UNIDENTIFIED_SENDER_TRUST_ROOT", "\"BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF\"" buildConfigField "String", "UNIDENTIFIED_SENDER_TRUST_ROOT", "\"BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF\""
buildConfigField "String", "ZKGROUP_SERVER_PUBLIC_PARAMS", "\"\"" 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 "String[]", "LANGUAGES", "new String[]{\"" + autoResConfig().collect { s -> s.replace('-r', '_') }.join('", "') + '"}'
buildConfigField "int", "CANONICAL_VERSION_CODE", "$canonicalVersionCode" 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 { ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
@@ -149,8 +160,9 @@ android {
} }
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 coreLibraryDesugaringEnabled true
targetCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JAVA_VERSION
targetCompatibility JAVA_VERSION
} }
packagingOptions { packagingOptions {
@@ -161,11 +173,16 @@ android {
exclude 'META-INF/LICENSE' exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE' exclude 'META-INF/NOTICE'
exclude 'META-INF/proguard/androidx-annotations.pro' exclude 'META-INF/proguard/androidx-annotations.pro'
exclude 'lib/*/libzkgroup.so' // TODO: GV2 Remove line to include .so when used exclude '/org/spongycastle/x509/CertPathReviewerMessages.properties'
exclude '/org/spongycastle/x509/CertPathReviewerMessages_de.properties'
} }
buildTypes { buildTypes {
debug { debug {
if (keystores['debug'] != null) {
signingConfig signingConfigs.debug
}
isDefault true
minifyEnabled true minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard/proguard-firebase-messaging.pro', 'proguard/proguard-firebase-messaging.pro',
@@ -188,9 +205,86 @@ android {
'proguard/proguard.cfg' 'proguard/proguard.cfg'
testProguardFiles 'proguard/proguard-automation.pro', testProguardFiles 'proguard/proguard-automation.pro',
'proguard/proguard.cfg' 'proguard/proguard.cfg'
buildConfigField "String", "BUILD_VARIANT_TYPE", "\"Debug\""
} }
staging { flipper {
initWith debug 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\""
}
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", "SIGNAL_URL", "\"https://textsecure-service-staging.whispersystems.org\""
buildConfigField "String", "STORAGE_URL", "\"https://storage-staging.signal.org\"" buildConfigField "String", "STORAGE_URL", "\"https://storage-staging.signal.org\""
@@ -198,34 +292,17 @@ android {
buildConfigField "String", "SIGNAL_CDN2_URL", "\"https://cdn2-staging.signal.org\"" 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_CONTACT_DISCOVERY_URL", "\"https://api-staging.directory.signal.org\""
buildConfigField "String", "SIGNAL_KEY_BACKUP_URL", "\"https://api-staging.backup.signal.org\"" buildConfigField "String", "SIGNAL_KEY_BACKUP_URL", "\"https://api-staging.backup.signal.org\""
buildConfigField "String", "CDS_MRENCLAVE", "\"ba4ebb438bc07713819ee6c98d94037747006d7df63fc9e44d2d6f1fec962a79\"" buildConfigField "String", "CDS_MRENCLAVE", "\"c98e00a4e3ff977a56afefe7362a27e4961e4f19e211febfbb19b897e6b80b15\""
buildConfigField "String", "KBS_ENCLAVE_NAME", "\"823a3b2c037ff0cbe305cc48928cfcc97c9ed4a8ca6d49af6f7d6981fb60a4e9\"" 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", "UNIDENTIFIED_SENDER_TRUST_ROOT", "\"BbqY1DzohE4NUZoVF+L18oUPrK3kILllLEJh2UnPSsEx\""
buildConfigField "String", "ZKGROUP_SERVER_PUBLIC_PARAMS", "\"\"" buildConfigField "String", "ZKGROUP_SERVER_PUBLIC_PARAMS", "\"ABSY21VckQcbSXVNCGRYJcfWHiAMZmpTtTELcDmxgdFbtp/bWsSxZdMKzfCp8rvIs8ocCU3B37fT3r4Mi5qAemeGeR2X+/YmOGR5ofui7tD5mDQfstAI9i+4WpMtIe8KC3wU5w3Inq3uNWVmoGtpKndsNfwJrCg0Hd9zmObhypUnSkfYn2ooMOOnBpfdanRtrvetZUayDMSC5iSRcXKpdls=\""
} buildConfigField "String", "MOBILE_COIN_ENVIRONMENT", "\"testnet\""
flipper { buildConfigField "String", "RECAPTCHA_PROOF_URL", "\"https://signalcaptchas.org/staging/challenge/generate.html\""
initWith debug
minifyEnabled false
}
release {
minifyEnabled true
proguardFiles = buildTypes.debug.proguardFiles
}
}
productFlavors { buildConfigField "String", "BUILD_ENVIRONMENT_TYPE", "\"Staging\""
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\""
} }
} }
@@ -241,6 +318,18 @@ android {
} }
} }
android.variantFilter { variant ->
def distribution = variant.getFlavors().get(0).name
def environment = variant.getFlavors().get(1).name
def buildType = variant.buildType.name
if (distribution == 'study' && buildType != 'perf' && buildType != 'mock') {
variant.setIgnore(true)
} else if (distribution != 'study' && buildType == 'mock') {
variant.setIgnore(true)
}
}
lintOptions { lintOptions {
abortOnError true abortOnError true
baseline file("lint-baseline.xml") baseline file("lint-baseline.xml")
@@ -255,29 +344,38 @@ android {
} }
dependencies { dependencies {
implementation 'androidx.appcompat:appcompat:1.1.0-beta01' implementation 'androidx.fragment:fragment-ktx:1.2.5'
implementation 'androidx.recyclerview:recyclerview:1.0.0' lintChecks project(':lintchecks')
implementation 'com.google.android.material:material:1.0.0'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
implementation ('androidx.appcompat:appcompat:1.2.0') {
force = true
}
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.legacy:legacy-support-v13:1.0.0'
implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.preference:preference:1.0.0' implementation 'androidx.preference:preference:1.0.0'
implementation 'androidx.legacy:legacy-preference-v14:1.0.0' implementation 'androidx.legacy:legacy-preference-v14:1.0.0'
implementation 'androidx.gridlayout:gridlayout:1.0.0' implementation 'androidx.gridlayout:gridlayout:1.0.0'
implementation 'androidx.exifinterface:exifinterface: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.multidex:multidex:2.0.1'
implementation 'androidx.navigation:navigation-fragment:2.1.0' implementation 'androidx.navigation:navigation-fragment:2.1.0'
implementation 'androidx.navigation:navigation-ui:2.1.0' implementation 'androidx.navigation:navigation-ui:2.1.0'
implementation 'androidx.lifecycle:lifecycle-extensions: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-viewmodel-savedstate:1.0.0-alpha05'
implementation 'androidx.lifecycle:lifecycle-common-java8:2.1.0' implementation 'androidx.lifecycle:lifecycle-common-java8:2.1.0'
implementation "androidx.camera:camera-core:1.0.0-beta01" implementation "androidx.camera:camera-core:1.0.0-beta11"
implementation "androidx.camera:camera-camera2:1.0.0-beta01" implementation "androidx.camera:camera-camera2:1.0.0-beta11"
implementation "androidx.camera:camera-lifecycle:1.0.0-beta01" 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.concurrent:concurrent-futures:1.0.0"
implementation "androidx.autofill:autofill:1.0.0" implementation "androidx.autofill:autofill:1.0.0"
implementation "androidx.biometric:biometric:1.1.0"
implementation('com.google.firebase:firebase-messaging:17.3.4') { implementation ('com.google.firebase:firebase-messaging:22.0.0') {
exclude group: 'com.google.firebase', module: 'firebase-core' exclude group: 'com.google.firebase', module: 'firebase-core'
exclude group: 'com.google.firebase', module: 'firebase-analytics' exclude group: 'com.google.firebase', module: 'firebase-analytics'
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector' exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
@@ -288,25 +386,37 @@ dependencies {
implementation 'com.google.android.exoplayer:exoplayer-core:2.9.1' 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: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.conscrypt:conscrypt-android:2.0.0'
implementation 'org.signal:aesgcmprovider:0.0.3' implementation 'org.signal:aesgcmprovider:0.0.3'
implementation project(':libsignal-service') implementation project(':libsignal-service')
implementation 'org.signal:zkgroup-android:0.4.1' 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.0'
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:argon2:13.1@aar'
implementation 'org.signal:ringrtc-android:1.3.1' implementation 'org.signal:ringrtc-android:2.10.1.1'
implementation "me.leolin:ShortcutBadger:1.1.16" implementation "me.leolin:ShortcutBadger:1.1.22"
implementation 'se.emilsjolander:stickylistheaders:2.7.0' implementation 'se.emilsjolander:stickylistheaders:2.7.0'
implementation 'com.jpardogo.materialtabstrip:library:1.0.9' implementation 'com.jpardogo.materialtabstrip:library:1.0.9'
implementation 'org.apache.httpcomponents:httpclient-android:4.3.5' implementation 'org.apache.httpcomponents:httpclient-android:4.3.5'
implementation 'com.github.chrisbanes:PhotoView:2.1.3' implementation 'com.github.chrisbanes:PhotoView:2.1.3'
implementation 'com.github.bumptech.glide:glide:4.11.0' implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' kapt 'com.github.bumptech.glide:compiler:4.11.0'
annotationProcessor 'androidx.annotation:annotation:1.1.0' kapt 'androidx.annotation:annotation:1.1.0'
implementation 'com.makeramen:roundedimageview:2.1.0' implementation 'com.makeramen:roundedimageview:2.1.0'
implementation 'com.pnikosis:materialish-progress:1.5' implementation 'com.pnikosis:materialish-progress:1.5'
implementation 'org.greenrobot:eventbus:3.0.0' implementation 'org.greenrobot:eventbus:3.0.0'
@@ -335,43 +445,49 @@ dependencies {
exclude group: 'com.android.support', module: 'recyclerview-v7' 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.codewaves.stickyheadergrid:stickyheadergrid:0.9.4'
implementation 'com.github.dmytrodanylyk.circular-progress-button:library:1.1.3-S2' 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') { implementation ('com.googlecode.ez-vcard:ez-vcard:0.9.11') {
exclude group: 'com.fasterxml.jackson.core' exclude group: 'com.fasterxml.jackson.core'
exclude group: 'org.freemarker' exclude group: 'org.freemarker'
} }
implementation 'dnsjava:dnsjava:2.1.9' implementation 'dnsjava:dnsjava:2.1.9'
flipperImplementation 'com.facebook.flipper:flipper:0.32.2' flipperImplementation 'com.facebook.flipper:flipper:0.91.0'
flipperImplementation 'com.facebook.soloader:soloader:0.8.2' flipperImplementation 'com.facebook.soloader:soloader:0.10.1'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
testImplementation 'org.assertj:assertj-core:3.11.1' testImplementation 'org.assertj:assertj-core:3.11.1'
testImplementation 'org.mockito:mockito-core:1.9.5' testImplementation 'org.mockito:mockito-core:2.8.9'
testImplementation 'org.powermock:powermock-api-mockito:1.6.1' testImplementation 'org.powermock:powermock-api-mockito2:1.7.4'
testImplementation 'org.powermock:powermock-module-junit4:1.6.1' testImplementation 'org.powermock:powermock-module-junit4:1.7.4'
testImplementation 'org.powermock:powermock-module-junit4-rule:1.6.1' testImplementation 'org.powermock:powermock-module-junit4-rule:1.7.4'
testImplementation 'org.powermock:powermock-classloading-xstream:1.6.1' testImplementation 'org.powermock:powermock-classloading-xstream:1.7.4'
testImplementation 'androidx.test:core:1.2.0' 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' 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'
androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 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"
} }
dependencyVerification { dependencyVerification {
configuration = '(play|website)(Debug|Release)RuntimeClasspath' configuration = '(play|website)(Prod|Staging)(Debug|Release)RuntimeClasspath'
} }
def assembleWebsiteDescriptor = { variant, file -> def assembleWebsiteDescriptor = { variant, file ->
if (file.exists()) { if (file.exists()) {
MessageDigest md = MessageDigest.getInstance("SHA-256"); MessageDigest md = MessageDigest.getInstance("SHA-256");
@@ -415,29 +531,29 @@ def signProductionRelease = { variant ->
task signProductionPlayRelease { task signProductionPlayRelease {
doLast { 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 { task signProductionWebsiteRelease {
doLast { 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') } File signedRelease = signProductionRelease(variant).find { it.name.contains('universal') }
assembleWebsiteDescriptor(variant, signedRelease) assembleWebsiteDescriptor(variant, signedRelease)
} }
} }
tasks.whenTaskAdded { task ->
if (task.name.equals("assemblePlayRelease")) {
task.finalizedBy signProductionPlayRelease
}
if (task.name.equals("assembleWebsiteRelease")) {
task.finalizedBy signProductionWebsiteRelease
}
}
def getLastCommitTimestamp() { def getLastCommitTimestamp() {
if (!(new File('.git').exists())) {
return System.currentTimeMillis().toString()
}
new ByteArrayOutputStream().withStream { os -> new ByteArrayOutputStream().withStream { os ->
def result = exec { def result = exec {
executable = 'git' executable = 'git'
@@ -448,3 +564,37 @@ def getLastCommitTimestamp() {
return os.toString() + "000" return os.toString() + "000"
} }
} }
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()
}
tasks.withType(Test) {
testLogging {
events "failed"
exceptionFormat "full"
showCauses true
showExceptions true
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;
}
}
+20 -1
View File
@@ -1,15 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<lint> <lint>
<!-- Wont pass lint or qa with a STOPSHIP in a comment -->
<issue id="StopShip" severity="fatal" />
<!-- L10N errors --> <!-- L10N errors -->
<!-- This is a runtime crash so we don't want to ship with this. --> <!-- This is a runtime crash so we don't want to ship with this. -->
<issue id="StringFormatMatches" severity="error" /> <issue id="StringFormatMatches" severity="error" />
<!-- L10N warnings --> <!-- L10N warnings -->
<issue id="MissingTranslation" severity="warning" /> <issue id="MissingTranslation" severity="ignore" />
<issue id="MissingQuantity" severity="warning" /> <issue id="MissingQuantity" severity="warning" />
<issue id="MissingDefaultResource" severity="error">
<ignore path="*/res/values-*/strings.xml" /> <!-- Ignore for non-English, excludeNonTranslatables task will remove these -->
</issue>
<issue id="ExtraTranslation" severity="warning" /> <issue id="ExtraTranslation" severity="warning" />
<issue id="ImpliedQuantity" severity="warning" /> <issue id="ImpliedQuantity" severity="warning" />
<issue id="TypographyDashes" severity="error" >
<ignore path="*/res/values-*/strings.xml" /> <!-- Ignore for non-English -->
</issue>
<issue id="CanvasSize" severity="error" /> <issue id="CanvasSize" severity="error" />
<issue id="HardcodedText" severity="error" /> <issue id="HardcodedText" severity="error" />
@@ -17,9 +26,19 @@
<issue id="ButtonOrder" severity="error" /> <issue id="ButtonOrder" severity="error" />
<issue id="ExtraTranslation" severity="warning" /> <issue id="ExtraTranslation" severity="warning" />
<!-- Custom lints -->
<issue id="LogNotSignal" severity="error" />
<issue id="LogNotAppSignal" severity="error" />
<issue id="LogTagInlined" severity="error" />
<issue id="AlertDialogBuilderUsage" severity="warning" />
<issue id="RestrictedApi" severity="error"> <issue id="RestrictedApi" severity="error">
<ignore path="*/org/thoughtcrime/securesms/mediasend/camerax/VideoCapture.java" /> <ignore path="*/org/thoughtcrime/securesms/mediasend/camerax/VideoCapture.java" />
<ignore path="*/org/thoughtcrime/securesms/mediasend/camerax/CameraXModule.java" /> <ignore path="*/org/thoughtcrime/securesms/mediasend/camerax/CameraXModule.java" />
<ignore path="*/org/thoughtcrime/securesms/conversation/*.java" />
<ignore path="*/org/thoughtcrime/securesms/lock/v2/CreateKbsPinViewModel.java" />
<ignore path="*/org/thoughtcrime/securesms/jobs/StickerPackDownloadJob.java" />
</issue> </issue>
</lint> </lint>
+29
View File
@@ -0,0 +1,29 @@
{
"data": [
{
"name": "Ottttooooooooo Ocataaaaaaaavius",
"number": "+1 (555) 555-5555",
"label": "Mobile"
},
{
"name": "Victor Von Doom Phd",
"number": "+1 (555) 123-4567",
"label": "Home"
},
{
"name": "Flash Thompson",
"number": "+1 (555) 435-1261",
"label": "Work"
},
{
"name": "Dr. Curtis Connors",
"number": "+1 (555) 992-1567",
"label": "Mobile"
},
{
"name": "Billy Russo",
"number": "+1 (555) 234-1516",
"label": "Mobile"
}
]
}
+8 -1
View File
@@ -5,5 +5,12 @@
<application <application
android:name=".FlipperApplicationContext" 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> </manifest>
@@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.database; package org.thoughtcrime.securesms.database;
import android.app.Application;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.text.TextUtils; import android.text.TextUtils;
@@ -14,14 +15,18 @@ import net.sqlcipher.DatabaseUtils;
import net.sqlcipher.database.SQLiteDatabase; import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteStatement; import net.sqlcipher.database.SQLiteStatement;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper; 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.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
/** /**
* A lot of this code is taken from {@link com.facebook.flipper.plugins.databases.impl.SqliteDatabaseDriver} * 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> { public class FlipperSqlCipherAdapter extends DatabaseDriver<FlipperSqlCipherAdapter.Descriptor> {
private static final String TAG = Log.tag(FlipperSqlCipherAdapter.class);
public FlipperSqlCipherAdapter(Context context) { public FlipperSqlCipherAdapter(Context context) {
super(context); super(context);
} }
@Override @Override
public List<Descriptor> getDatabases() { 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 @Override
@@ -215,7 +238,12 @@ public class FlipperSqlCipherAdapter extends DatabaseDriver<FlipperSqlCipherAdap
case Cursor.FIELD_TYPE_FLOAT: case Cursor.FIELD_TYPE_FLOAT:
return cursor.getDouble(column); return cursor.getDouble(column);
case Cursor.FIELD_TYPE_BLOB: 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: case Cursor.FIELD_TYPE_STRING:
default: default:
return cursor.getString(column); return cursor.getString(column);
@@ -223,9 +251,9 @@ public class FlipperSqlCipherAdapter extends DatabaseDriver<FlipperSqlCipherAdap
} }
static class Descriptor implements DatabaseDescriptor { static class Descriptor implements DatabaseDescriptor {
private final SQLCipherOpenHelper sqlCipherOpenHelper; private final SignalDatabase sqlCipherOpenHelper;
Descriptor(@NonNull SQLCipherOpenHelper sqlCipherOpenHelper) { Descriptor(@NonNull SignalDatabase sqlCipherOpenHelper) {
this.sqlCipherOpenHelper = sqlCipherOpenHelper; this.sqlCipherOpenHelper = sqlCipherOpenHelper;
} }
@@ -235,11 +263,11 @@ public class FlipperSqlCipherAdapter extends DatabaseDriver<FlipperSqlCipherAdap
} }
public @NonNull SQLiteDatabase getReadable() { public @NonNull SQLiteDatabase getReadable() {
return sqlCipherOpenHelper.getReadableDatabase(); return sqlCipherOpenHelper.getSqlCipherDatabase();
} }
public @NonNull SQLiteDatabase getWritable() { public @NonNull SQLiteDatabase getWritable() {
return sqlCipherOpenHelper.getWritableDatabase(); return sqlCipherOpenHelper.getSqlCipherDatabase();
} }
} }
} }
-4
View File
@@ -1,4 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="app_name">Signal (Flipper)</string>
</resources>
@@ -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>
+219 -90
View File
@@ -3,9 +3,9 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="org.thoughtcrime.securesms"> 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:label="Access to TextSecure Secrets"
android:protectionLevel="signature" /> android:protectionLevel="signature" />
@@ -35,8 +35,10 @@
<uses-permission android:name="android.permission.SEND_SMS"/> <uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.WRITE_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_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" /> <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.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS" /> <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' --> <!-- So we can add a TextSecure 'Account' -->
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" /> <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
@@ -113,13 +114,22 @@
<meta-data android:name="google_analytics_adid_collection_enabled" android:value="false" /> <meta-data android:name="google_analytics_adid_collection_enabled" android:value="false" />
<meta-data android:name="firebase_messaging_auto_init_enabled" android:value="false" /> <meta-data android:name="firebase_messaging_auto_init_enabled" android:value="false" />
<activity android:name="org.thoughtcrime.securesms.WebRtcCallActivity" <activity android:name=".WebRtcCallActivity"
android:theme="@style/TextSecure.LightTheme.WebRTCCall" android:theme="@style/TextSecure.DarkTheme.WebRTCCall"
android:excludeFromRecents="true" android:excludeFromRecents="true"
android:screenOrientation="portrait" android:screenOrientation="portrait"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|screenSize|fontScale" android:supportsPictureInPicture="true"
android:windowSoftInputMode="stateAlwaysHidden"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
android:taskAffinity=".calling"
android:launchMode="singleTask"/> android:launchMode="singleTask"/>
<activity android:name=".messagerequests.CalleeMustAcceptMessageRequestActivity"
android:theme="@style/TextSecure.DarkNoActionBar"
android:screenOrientation="portrait"
android:noHistory="true"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".InviteActivity" <activity android:name=".InviteActivity"
android:theme="@style/Signal.Light.NoActionBar.Invite" android:theme="@style/Signal.Light.NoActionBar.Invite"
android:windowSoftInputMode="stateHidden" android:windowSoftInputMode="stateHidden"
@@ -127,7 +137,7 @@
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value="org.thoughtcrime.securesms.MainActivity" /> android:value=".MainActivity" />
</activity> </activity>
<activity android:name=".PromptMmsActivity" <activity android:name=".PromptMmsActivity"
@@ -143,17 +153,28 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="tsdevice"/> <data android:scheme="tsdevice"/>
</intent-filter> </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>
<activity android:name=".preferences.MmsPreferencesActivity" <activity android:name=".preferences.MmsPreferencesActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> 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" <activity android:name=".sharing.ShareActivity"
android:theme="@style/TextSecure.LightNoActionBar" android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:excludeFromRecents="true" android:excludeFromRecents="true"
android:launchMode="singleTask" android:launchMode="singleTask"
android:taskAffinity="" android:taskAffinity=""
android:noHistory="true"
android:windowSoftInputMode="stateHidden" android:windowSoftInputMode="stateHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
<intent-filter> <intent-filter>
@@ -182,7 +203,7 @@
</activity> </activity>
<activity android:name=".stickers.StickerPackPreviewActivity" <activity android:name=".stickers.StickerPackPreviewActivity"
android:theme="@style/TextSecure.LightNoActionBar" android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:launchMode="singleTask" android:launchMode="singleTask"
android:noHistory="true" android:noHistory="true"
android:windowSoftInputMode="stateHidden" android:windowSoftInputMode="stateHidden"
@@ -221,6 +242,38 @@
</activity-alias> </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" <activity android:name=".conversation.ConversationActivity"
android:windowSoftInputMode="stateUnchanged" android:windowSoftInputMode="stateUnchanged"
android:launchMode="singleTask" android:launchMode="singleTask"
@@ -231,6 +284,11 @@
android:value="org.thoughtcrime.securesms.MainActivity" /> android:value="org.thoughtcrime.securesms.MainActivity" />
</activity> </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=".longmessage.LongMessageActivity" />
<activity android:name=".conversation.ConversationPopupActivity" <activity android:name=".conversation.ConversationPopupActivity"
@@ -241,19 +299,19 @@
android:theme="@style/TextSecure.LightTheme.Popup" android:theme="@style/TextSecure.LightTheme.Popup"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" /> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" />
<activity android:name=".MessageDetailsActivity" <activity android:name=".messagedetails.MessageDetailsActivity"
android:label="@string/AndroidManifest__message_details"
android:windowSoftInputMode="stateHidden" android:windowSoftInputMode="stateHidden"
android:launchMode="singleTask" android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".GroupCreateActivity" <activity android:name=".groups.ui.invitesandrequests.ManagePendingAndRequestingMembersActivity"
android:windowSoftInputMode="stateVisible" android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:theme="@style/Theme.Signal.DayNight.NoActionBar" />
<activity android:name=".groups.ui.pendingmemberinvites.PendingMemberInvitesActivity" <activity android:name=".recipients.ui.disappearingmessages.RecipientDisappearingMessagesActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:theme="@style/TextSecure.LightNoActionBar" /> android:theme="@style/Signal.DayNight.NoActionBar"
android:windowSoftInputMode="adjustResize"/>
<activity android:name=".DatabaseMigrationActivity" <activity android:name=".DatabaseMigrationActivity"
android:theme="@style/NoAnimation.Theme.AppCompat.Light.DarkActionBar" android:theme="@style/NoAnimation.Theme.AppCompat.Light.DarkActionBar"
@@ -268,7 +326,7 @@
<activity android:name=".PassphraseCreateActivity" <activity android:name=".PassphraseCreateActivity"
android:label="@string/AndroidManifest__create_passphrase" android:label="@string/AndroidManifest__create_passphrase"
android:windowSoftInputMode="stateUnchanged" android:windowSoftInputMode="stateUnchanged"
android:theme="@style/TextSecure.LightNoActionBar" android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:launchMode="singleTask" android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
@@ -278,7 +336,7 @@
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".NewConversationActivity" <activity android:name=".NewConversationActivity"
android:theme="@style/TextSecure.LightNoActionBar" android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:windowSoftInputMode="stateAlwaysVisible" android:windowSoftInputMode="stateAlwaysVisible"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
@@ -288,7 +346,7 @@
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".giph.ui.GiphyActivity" <activity android:name=".giph.ui.GiphyActivity"
android:theme="@style/TextSecure.LightNoActionBar" android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:windowSoftInputMode="stateHidden" android:windowSoftInputMode="stateHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
@@ -305,14 +363,43 @@
<activity android:name=".VerifyIdentityActivity" <activity android:name=".VerifyIdentityActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".ApplicationPreferencesActivity" <activity android:name=".components.settings.app.AppSettingsActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:theme="@style/Signal.DayNight.NoActionBar"
android:windowSoftInputMode="adjustResize">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.NOTIFICATION_PREFERENCES" /> <category android:name="android.intent.category.NOTIFICATION_PREFERENCES" />
</intent-filter> </intent-filter>
</activity> </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" <activity android:name=".registration.RegistrationNavigationActivity"
android:launchMode="singleTask" android:launchMode="singleTask"
android:theme="@style/TextSecure.LightRegistrationTheme" android:theme="@style/TextSecure.LightRegistrationTheme"
@@ -337,18 +424,22 @@
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".logsubmit.SubmitDebugLogActivity" <activity android:name=".logsubmit.SubmitDebugLogActivity"
android:label="@string/AndroidManifest__log_submit"
android:windowSoftInputMode="stateHidden" android:windowSoftInputMode="stateHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".MediaPreviewActivity" <activity android:name=".MediaPreviewActivity"
android:label="@string/AndroidManifest__media_preview" android:label="@string/AndroidManifest__media_preview"
android:windowSoftInputMode="stateHidden" android:windowSoftInputMode="stateHidden"
android:launchMode="singleTask" android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> 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"/>
<activity android:name=".mediaoverview.MediaOverviewActivity" <activity android:name=".mediaoverview.MediaOverviewActivity"
android:theme="@style/TextSecure.LightNoActionBar" android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:windowSoftInputMode="stateHidden" android:windowSoftInputMode="stateHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
@@ -399,25 +490,28 @@
</activity> </activity>
<activity android:name=".RecipientPreferenceActivity"
android:theme="@style/TextSecure.LightNoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".mediasend.AvatarSelectionActivity" <activity android:name=".mediasend.AvatarSelectionActivity"
android:theme="@style/TextSecure.FullScreenMedia" android:theme="@style/TextSecure.FullScreenMedia"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".BlockedContactsActivity" <activity android:name=".blocked.BlockedUsersActivity"
android:theme="@style/TextSecure.LightTheme" android:theme="@style/TextSecure.LightTheme"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".scribbles.ImageEditorStickerSelectActivity" <activity android:name=".scribbles.ImageEditorStickerSelectActivity"
android:theme="@style/TextSecure.DarkTheme" android:theme="@style/Signal.DayNight.NoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".profiles.edit.EditProfileActivity" <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:theme="@style/TextSecure.LightRegistrationTheme"
android:windowSoftInputMode="stateVisible"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".lock.v2.CreateKbsPinActivity" <activity android:name=".lock.v2.CreateKbsPinActivity"
@@ -430,17 +524,14 @@
android:windowSoftInputMode="adjustResize" android:windowSoftInputMode="adjustResize"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".ClearProfileAvatarActivity" <activity android:name=".ClearAvatarPromptActivity"
android:theme="@style/Theme.AppCompat.Dialog.Alert" android:theme="@style/Theme.AppCompat.Dialog.Alert"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" android:icon="@drawable/clear_profile_avatar"
android:icon="@drawable/clear_profile_avatar" android:label="@string/AndroidManifest_remove_photo"
android:label="@string/AndroidManifest_remove_photo"> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<intent-filter> <activity android:name=".contacts.TurnOffContactJoinedNotificationsActivity"
<action android:name="org.thoughtcrime.securesms.action.CLEAR_PROFILE_PHOTO"/> android:theme="@style/Theme.AppCompat.Dialog.Alert" />
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name=".messagerequests.MessageRequestMegaphoneActivity" <activity android:name=".messagerequests.MessageRequestMegaphoneActivity"
android:theme="@style/TextSecure.LightRegistrationTheme" android:theme="@style/TextSecure.LightRegistrationTheme"
@@ -452,38 +543,85 @@
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".contactshare.ContactNameEditActivity" <activity android:name=".contactshare.ContactNameEditActivity"
android:theme="@style/TextSecure.LightNoActionBar" android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".contactshare.SharedContactDetailsActivity" <activity android:name=".contactshare.SharedContactDetailsActivity"
android:theme="@style/TextSecure.LightNoActionBar" android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".ShortcutLauncherActivity" <activity android:name=".ShortcutLauncherActivity"
android:theme="@style/TextSecure.LightNoActionBar" android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:exported="true" android:exported="true"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity <activity
android:name=".maps.PlacePickerActivity" android:name=".maps.PlacePickerActivity"
android:label="@string/PlacePickerActivity_title" android:label="@string/PlacePickerActivity_title"
android:theme="@style/TextSecure.LightNoActionBar" android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".MainActivity" <activity android:name=".MainActivity"
android:theme="@style/TextSecure.LightNoActionBar" android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" /> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" />
<activity android:name=".pin.PinRestoreActivity" <activity android:name=".pin.PinRestoreActivity"
android:theme="@style/TextSecure.LightNoActionBar" android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" /> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" />
<activity android:name=".groups.ui.creategroup.CreateGroupActivity"
android:theme="@style/Theme.Signal.DayNight.NoActionBar" />
<service android:enabled="true" android:name="org.thoughtcrime.securesms.service.WebRtcCallService"/> <activity android:name=".groups.ui.addtogroup.AddToGroupsActivity"
android:theme="@style/Theme.Signal.DayNight.NoActionBar" />
<activity android:name=".groups.ui.addmembers.AddMembersActivity"
android:theme="@style/Theme.Signal.DayNight.NoActionBar" />
<activity android:name=".groups.ui.creategroup.details.AddGroupDetailsActivity"
android:theme="@style/Theme.Signal.DayNight.NoActionBar" />
<activity android:name=".groups.ui.chooseadmin.ChooseNewAdminActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" />
<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:name=".service.ApplicationMigrationService"/>
<service android:enabled="true" android:exported="false" android:name=".service.KeyCachingService"/> <service android:enabled="true" android:exported="false" android:name=".service.KeyCachingService"/>
<service android:enabled="true" android:name=".service.IncomingMessageObserver$ForegroundService"/> <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" <service android:name=".service.QuickResponseService"
android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE" android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
@@ -522,7 +660,9 @@
<service android:name=".service.GenericForegroundService"/> <service android:name=".service.GenericForegroundService"/>
<service android:name=".gcm.FcmService"> <service android:name=".gcm.FcmFetchService" />
<service android:name=".gcm.FcmReceiveService">
<intent-filter> <intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" /> <action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter> </intent-filter>
@@ -577,36 +717,33 @@
</intent-filter> </intent-filter>
</receiver> </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=".service.ExpirationListener" />
<receiver android:name=".revealable.ViewOnceMessageManager$ViewOnceAlarm" /> <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" <provider android:name=".providers.PartProvider"
android:grantUriPermissions="true" android:grantUriPermissions="true"
android:exported="false" 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" <provider android:name=".providers.MmsBodyProvider"
android:grantUriPermissions="true" android:grantUriPermissions="true"
android:exported="false" android:exported="false"
android:authorities="org.thoughtcrime.provider.securesms.mms" /> android:authorities="${applicationId}.mms" />
<provider android:name="androidx.core.content.FileProvider" <provider android:name="androidx.core.content.FileProvider"
android:authorities="org.thoughtcrime.securesms.fileprovider" android:authorities="${applicationId}.fileprovider"
android:exported="false" android:exported="false"
android:grantUriPermissions="true"> android:grantUriPermissions="true">
@@ -615,23 +752,19 @@
</provider> </provider>
<provider android:name=".database.DatabaseContentProviders$Conversation" <provider android:name=".database.DatabaseContentProviders$Conversation"
android:authorities="org.thoughtcrime.securesms.database.conversation" android:authorities="${applicationId}.database.conversation"
android:exported="false" />
<provider android:name=".database.DatabaseContentProviders$ConversationList"
android:authorities="org.thoughtcrime.securesms.database.conversationlist"
android:exported="false" /> android:exported="false" />
<provider android:name=".database.DatabaseContentProviders$Attachment" <provider android:name=".database.DatabaseContentProviders$Attachment"
android:authorities="org.thoughtcrime.securesms.database.attachment" android:authorities="${applicationId}.database.attachment"
android:exported="false" /> android:exported="false" />
<provider android:name=".database.DatabaseContentProviders$Sticker" <provider android:name=".database.DatabaseContentProviders$Sticker"
android:authorities="org.thoughtcrime.securesms.database.sticker" android:authorities="${applicationId}.database.sticker"
android:exported="false" /> android:exported="false" />
<provider android:name=".database.DatabaseContentProviders$StickerPack" <provider android:name=".database.DatabaseContentProviders$StickerPack"
android:authorities="org.thoughtcrime.securesms.database.stickerpack" android:authorities="${applicationId}.database.stickerpack"
android:exported="false" /> android:exported="false" />
<receiver android:name=".service.BootReceiver"> <receiver android:name=".service.BootReceiver">
@@ -659,6 +792,13 @@
</intent-filter> </intent-filter>
</receiver> </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"> <receiver android:name=".service.LocalBackupListener">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.BOOT_COMPLETED" />
@@ -677,11 +817,7 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver android:name=".notifications.MessageNotifier$ReminderReceiver"> <receiver android:name=".notifications.MessageNotifier$ReminderReceiver"/>
<intent-filter>
<action android:name="org.thoughtcrime.securesms.MessageNotifier.REMINDER_ACTION"/>
</intent-filter>
</receiver>
<receiver android:name=".notifications.DeleteNotificationReceiver"> <receiver android:name=".notifications.DeleteNotificationReceiver">
<intent-filter> <intent-filter>
@@ -728,12 +864,5 @@
<uses-library android:name="org.apache.http.legacy" android:required="false"/> <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> </application>
</manifest> </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.
@@ -0,0 +1,824 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.camera.view;
import android.Manifest.permission;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Display;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.Surface;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.RequiresPermission;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraSelector;
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.signal.core.util.logging.Log;
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 #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.
*/
@RequiresApi(21)
@SuppressLint("RestrictedApi")
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;
private static final String EXTRA_SUPER = "super";
private static final String EXTRA_ZOOM_RATIO = "zoom_ratio";
private static final String EXTRA_PINCH_TO_ZOOM_ENABLED = "pinch_to_zoom_enabled";
private static final String EXTRA_FLASH = "flash";
private static final String EXTRA_MAX_VIDEO_DURATION = "max_video_duration";
private static final String EXTRA_MAX_VIDEO_SIZE = "max_video_size";
private static final String EXTRA_SCALE_TYPE = "scale_type";
private static final String EXTRA_CAMERA_DIRECTION = "camera_direction";
private static final String EXTRA_CAPTURE_MODE = "captureMode";
private static final int LENS_FACING_NONE = 0;
private static final int LENS_FACING_FRONT = 1;
private static final int LENS_FACING_BACK = 2;
private static final int FLASH_MODE_AUTO = 1;
private static final int FLASH_MODE_ON = 2;
private static final int FLASH_MODE_OFF = 4;
// For tap-to-focus
private long mDownEventTimestamp;
// For pinch-to-zoom
private PinchToZoomGestureDetector mPinchToZoomGestureDetector;
private boolean mIsPinchToZoomEnabled = true;
SignalCameraXModule mCameraModule;
private final DisplayManager.DisplayListener mDisplayListener =
new DisplayListener() {
@Override
public void onDisplayAdded(int displayId) {
}
@Override
public void onDisplayRemoved(int displayId) {
}
@Override
public void onDisplayChanged(int displayId) {
mCameraModule.invalidateView();
}
};
private PreviewView mPreviewView;
// For accessibility event
private MotionEvent mUpEvent;
public SignalCameraView(@NonNull Context context) {
this(context, null);
}
public SignalCameraView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public SignalCameraView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
@RequiresApi(21)
public SignalCameraView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
/**
* Binds control of the camera used by this view to the given lifecycle.
*
* <p>This links opening/closing the camera to the given lifecycle. The camera will not operate
* unless this method is called with a valid {@link LifecycleOwner} that is not in the {@link
* androidx.lifecycle.Lifecycle.State#DESTROYED} state. Call this method only once camera
* permissions have been obtained.
*
* <p>Once the provided lifecycle has transitioned to a {@link
* androidx.lifecycle.Lifecycle.State#DESTROYED} state, CameraView must be bound to a new
* lifecycle through this method in order to operate the camera.
*
* @param lifecycleOwner The lifecycle that will control this view's camera
* @throws IllegalArgumentException if provided lifecycle is in a {@link
* androidx.lifecycle.Lifecycle.State#DESTROYED} state.
* @throws IllegalStateException if camera permissions are not granted.
*/
@RequiresPermission(permission.CAMERA)
public void bindToLifecycle(@NonNull LifecycleOwner lifecycleOwner) {
mCameraModule.bindToLifecycle(lifecycleOwner);
}
private void init(Context context, @Nullable AttributeSet attrs) {
addView(mPreviewView = new PreviewView(getContext()), 0 /* view position */);
mCameraModule = new SignalCameraXModule(this);
if (attrs != null) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CameraView);
setScaleType(
PreviewView.ScaleType.fromId(
a.getInteger(R.styleable.CameraView_scaleType,
getScaleType().getId())));
setPinchToZoomEnabled(
a.getBoolean(
R.styleable.CameraView_pinchToZoomEnabled, isPinchToZoomEnabled()));
setCaptureMode(
CaptureMode.fromId(
a.getInteger(R.styleable.CameraView_captureMode,
getCaptureMode().getId())));
int lensFacing = a.getInt(R.styleable.CameraView_lensFacing, LENS_FACING_BACK);
switch (lensFacing) {
case LENS_FACING_NONE:
setCameraLensFacing(null);
break;
case LENS_FACING_FRONT:
setCameraLensFacing(CameraSelector.LENS_FACING_FRONT);
break;
case LENS_FACING_BACK:
setCameraLensFacing(CameraSelector.LENS_FACING_BACK);
break;
default:
// Unhandled event.
}
int flashMode = a.getInt(R.styleable.CameraView_flash, 0);
switch (flashMode) {
case FLASH_MODE_AUTO:
setFlash(ImageCapture.FLASH_MODE_AUTO);
break;
case FLASH_MODE_ON:
setFlash(ImageCapture.FLASH_MODE_ON);
break;
case FLASH_MODE_OFF:
setFlash(ImageCapture.FLASH_MODE_OFF);
break;
default:
// Unhandled event.
}
a.recycle();
}
if (getBackground() == null) {
setBackgroundColor(0xFF111111);
}
mPinchToZoomGestureDetector = new PinchToZoomGestureDetector(context);
}
@Override
@NonNull
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
@Override
@NonNull
protected Parcelable onSaveInstanceState() {
// TODO(b/113884082): Decide what belongs here or what should be invalidated on
// configuration
// change
Bundle state = new Bundle();
state.putParcelable(EXTRA_SUPER, super.onSaveInstanceState());
state.putInt(EXTRA_SCALE_TYPE, getScaleType().getId());
state.putFloat(EXTRA_ZOOM_RATIO, getZoomRatio());
state.putBoolean(EXTRA_PINCH_TO_ZOOM_ENABLED, isPinchToZoomEnabled());
state.putString(EXTRA_FLASH, FlashModeConverter.nameOf(getFlash()));
state.putLong(EXTRA_MAX_VIDEO_DURATION, getMaxVideoDuration());
state.putLong(EXTRA_MAX_VIDEO_SIZE, getMaxVideoSize());
if (getCameraLensFacing() != null) {
state.putString(EXTRA_CAMERA_DIRECTION,
LensFacingConverter.nameOf(getCameraLensFacing()));
}
state.putInt(EXTRA_CAPTURE_MODE, getCaptureMode().getId());
return state;
}
@Override
protected void onRestoreInstanceState(@Nullable Parcelable savedState) {
// TODO(b/113884082): Decide what belongs here or what should be invalidated on
// configuration
// change
if (savedState instanceof Bundle) {
Bundle state = (Bundle) savedState;
super.onRestoreInstanceState(state.getParcelable(EXTRA_SUPER));
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)));
setMaxVideoDuration(state.getLong(EXTRA_MAX_VIDEO_DURATION));
setMaxVideoSize(state.getLong(EXTRA_MAX_VIDEO_SIZE));
String lensFacingString = state.getString(EXTRA_CAMERA_DIRECTION);
setCameraLensFacing(
TextUtils.isEmpty(lensFacingString)
? null
: LensFacingConverter.valueOf(lensFacingString));
setCaptureMode(CaptureMode.fromId(state.getInt(EXTRA_CAPTURE_MODE)));
} else {
super.onRestoreInstanceState(savedState);
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
DisplayManager dpyMgr =
(DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE);
dpyMgr.registerDisplayListener(mDisplayListener, new Handler(Looper.getMainLooper()));
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
DisplayManager dpyMgr =
(DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE);
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;
}
// TODO(b/124269166): Rethink how we can handle permissions here.
@SuppressLint("MissingPermission")
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Since bindToLifecycle will depend on the measured dimension, only call it when measured
// dimension is not 0x0
if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0) {
mCameraModule.bindToLifecycleAfterViewMeasured();
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
// TODO(b/124269166): Rethink how we can handle permissions here.
@SuppressLint("MissingPermission")
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
// In case that the CameraView size is always set as 0x0, we still need to trigger to force
// binding to lifecycle
mCameraModule.bindToLifecycleAfterViewMeasured();
mCameraModule.invalidateView();
super.onLayout(changed, left, top, right, bottom);
}
/**
* @return One of {@link Surface#ROTATION_0}, {@link Surface#ROTATION_90}, {@link
* Surface#ROTATION_180}, {@link Surface#ROTATION_270}.
*/
int getDisplaySurfaceRotation() {
Display display = getDisplay();
// Null when the View is detached. If we were in the middle of a background operation,
// better to not NPE. When the background operation finishes, it'll realize that the camera
// was closed.
if (display == null) {
return 0;
}
return display.getRotation();
}
/**
* Returns the scale type used to scale the preview.
*
* @return The current {@link PreviewView.ScaleType}.
*/
@NonNull
public PreviewView.ScaleType getScaleType() {
return mPreviewView.getScaleType();
}
/**
* Sets the view finder scale type.
*
* <p>This controls how the view finder should be scaled and positioned within the view.
*
* @param scaleType The desired {@link PreviewView.ScaleType}.
*/
public void setScaleType(@NonNull PreviewView.ScaleType scaleType) {
mPreviewView.setScaleType(scaleType);
}
/**
* Returns the scale type used to scale the preview.
*
* @return The current {@link CaptureMode}.
*/
@NonNull
public CaptureMode getCaptureMode() {
return mCameraModule.getCaptureMode();
}
/**
* Sets the CameraView capture mode
*
* <p>This controls only image or video capture function is enabled or both are enabled.
*
* @param captureMode The desired {@link CaptureMode}.
*/
public void setCaptureMode(@NonNull CaptureMode captureMode) {
mCameraModule.setCaptureMode(captureMode);
}
/**
* Returns the maximum duration of videos, or {@link #INDEFINITE_VIDEO_DURATION} if there is no
* timeout.
*
* @hide Not currently implemented.
*/
@RestrictTo(Scope.LIBRARY_GROUP)
public long getMaxVideoDuration() {
return mCameraModule.getMaxVideoDuration();
}
/**
* 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);
}
/**
* Returns the maximum size of videos in bytes, or {@link #INDEFINITE_VIDEO_SIZE} if there is no
* timeout.
*/
private long getMaxVideoSize() {
return mCameraModule.getMaxVideoSize();
}
/**
* 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) {
mCameraModule.setMaxVideoSize(size);
}
/**
* Takes a picture, and calls {@link OnImageCapturedCallback#onCaptureSuccess(ImageProxy)}
* once when done.
*
* @param executor The executor in which the callback methods will be run.
* @param callback Callback which will receive success or failure callbacks.
*/
public void takePicture(@NonNull Executor executor, @NonNull OnImageCapturedCallback callback) {
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 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.
*/
public void startRecording(@NonNull VideoCapture.OutputFileOptions outputFileOptions,
@NonNull Executor executor,
@NonNull OnVideoSavedCallback callback) {
mCameraModule.startRecording(outputFileOptions, executor, callback);
}
/** Stops an in progress video. */
public void stopRecording() {
mCameraModule.stopRecording();
}
/** @return True if currently recording. */
public boolean isRecording() {
return mCameraModule.isRecording();
}
/**
* Queries whether the current device has a camera with the specified direction.
*
* @return True if the device supports the direction.
* @throws IllegalStateException if the CAMERA permission is not currently granted.
*/
@RequiresPermission(permission.CAMERA)
public boolean hasCameraWithLensFacing(@CameraSelector.LensFacing int lensFacing) {
return mCameraModule.hasCameraWithLensFacing(lensFacing);
}
/**
* Toggles between the primary front facing camera and the primary back facing camera.
*
* <p>This will have no effect if not already bound to a lifecycle via {@link
* #bindToLifecycle(LifecycleOwner)}.
*/
public void toggleCamera() {
mCameraModule.toggleCamera();
}
/**
* Sets the desired camera by specifying desired lensFacing.
*
* <p>This will choose the primary camera with the specified camera lensFacing.
*
* <p>If called before {@link #bindToLifecycle(LifecycleOwner)}, this will set the camera to be
* used when first bound to the lifecycle. If the specified lensFacing is not supported by the
* device, as determined by {@link #hasCameraWithLensFacing(int)}, the first supported
* lensFacing will be chosen when {@link #bindToLifecycle(LifecycleOwner)} is called.
*
* <p>If called with {@code null} AFTER binding to the lifecycle, the behavior would be
* equivalent to unbind the use cases without the lifecycle having to be destroyed.
*
* @param lensFacing The desired camera lensFacing.
*/
public void setCameraLensFacing(@Nullable Integer lensFacing) {
mCameraModule.setCameraLensFacing(lensFacing);
}
/** Returns the currently selected lensFacing. */
@Nullable
public Integer getCameraLensFacing() {
return mCameraModule.getLensFacing();
}
/** Gets the active flash strategy. */
@ImageCapture.FlashMode
public int getFlash() {
return mCameraModule.getFlash();
}
// Begin Signal Custom Code Block
public boolean hasFlash() {
return mCameraModule.hasFlash();
}
// End Signal Custom Code Block
/** Sets the active flash strategy. */
public void setFlash(@ImageCapture.FlashMode int flashMode) {
mCameraModule.setFlash(flashMode);
}
private long delta() {
return System.currentTimeMillis() - mDownEventTimestamp;
}
@Override
public boolean onTouchEvent(@NonNull MotionEvent event) {
// Disable pinch-to-zoom and tap-to-focus while the camera module is paused.
if (mCameraModule.isPaused()) {
return false;
}
// Only forward the event to the pinch-to-zoom gesture detector when pinch-to-zoom is
// enabled.
if (isPinchToZoomEnabled()) {
mPinchToZoomGestureDetector.onTouchEvent(event);
}
if (event.getPointerCount() == 2 && isPinchToZoomEnabled() && isZoomSupported()) {
return true;
}
// Camera focus
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownEventTimestamp = System.currentTimeMillis();
break;
case MotionEvent.ACTION_UP:
if (delta() < ViewConfiguration.getLongPressTimeout()
&& mCameraModule.isBoundToLifecycle()) {
mUpEvent = event;
performClick();
}
break;
default:
// Unhandled event.
return false;
}
return true;
}
/**
* Focus the position of the touch event, or focus the center of the preview for
* accessibility events
*/
@Override
public boolean performClick() {
super.performClick();
final float x = (mUpEvent != null) ? mUpEvent.getX() : getX() + getWidth() / 2f;
final float y = (mUpEvent != null) ? mUpEvent.getY() : getY() + getHeight() / 2f;
mUpEvent = null;
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,
FocusMeteringAction.FLAG_AF).addPoint(aePoint,
FocusMeteringAction.FLAG_AE).build());
Futures.addCallback(future, new FutureCallback<FocusMeteringResult>() {
@Override
public void onSuccess(@Nullable FocusMeteringResult result) {
}
@Override
public void onFailure(Throwable t) {
// Throw the unexpected error.
throw new RuntimeException(t);
}
}, CameraXExecutors.directExecutor());
} else {
Logger.d(TAG, "cannot access camera");
}
return true;
}
float rangeLimit(float val, float max, float min) {
return Math.min(Math.max(val, min), max);
}
/**
* Returns whether the view allows pinch-to-zoom.
*
* @return True if pinch to zoom is enabled.
*/
public boolean isPinchToZoomEnabled() {
return mIsPinchToZoomEnabled;
}
/**
* Sets whether the view should allow pinch-to-zoom.
*
* <p>When enabled, the user can pinch the camera to zoom in/out. This only has an effect if the
* bound camera supports zoom.
*
* @param enabled True to enable pinch-to-zoom.
*/
public void setPinchToZoomEnabled(boolean enabled) {
mIsPinchToZoomEnabled = enabled;
}
/**
* Returns the current zoom ratio.
*
* @return The current zoom ratio.
*/
public float getZoomRatio() {
return mCameraModule.getZoomRatio();
}
/**
* Sets the current zoom ratio.
*
* <p>Valid zoom values range from {@link #getMinZoomRatio()} to {@link #getMaxZoomRatio()}.
*
* @param zoomRatio The requested zoom ratio.
*/
public void setZoomRatio(float zoomRatio) {
mCameraModule.setZoomRatio(zoomRatio);
}
/**
* Returns the minimum zoom ratio.
*
* <p>For most cameras this should return a zoom ratio of 1. A zoom ratio of 1 corresponds to a
* non-zoomed image.
*
* @return The minimum zoom ratio.
*/
public float getMinZoomRatio() {
return mCameraModule.getMinZoomRatio();
}
/**
* Returns the maximum zoom ratio.
*
* <p>The zoom ratio corresponds to the ratio between both the widths and heights of a
* non-zoomed image and a maximally zoomed image for the selected camera.
*
* @return The maximum zoom ratio.
*/
public float getMaxZoomRatio() {
return mCameraModule.getMaxZoomRatio();
}
/**
* Returns whether the bound camera supports zooming.
*
* @return True if the camera supports zooming.
*/
public boolean isZoomSupported() {
return mCameraModule.isZoomSupported();
}
/**
* Turns on/off torch.
*
* @param torch True to turn on torch, false to turn off torch.
*/
public void enableTorch(boolean torch) {
mCameraModule.enableTorch(torch);
}
/**
* Returns current torch status.
*
* @return true if torch is on , otherwise false
*/
public boolean isTorchOn() {
return mCameraModule.isTorchOn();
}
/**
* The capture mode used by CameraView.
*
* <p>This enum can be used to determine which capture mode will be enabled for {@link
* SignalCameraView}.
*/
public enum CaptureMode {
/** A mode where image capture is enabled. */
IMAGE(0),
/** A mode where video capture is enabled. */
VIDEO(1),
/**
* A mode where both image capture and video capture are simultaneously enabled. Note that
* this mode may not be available on every device.
*/
MIXED(2);
private final int mId;
int getId() {
return mId;
}
CaptureMode(int id) {
mId = id;
}
static CaptureMode fromId(int id) {
for (CaptureMode f : values()) {
if (f.mId == id) {
return f;
}
}
throw new IllegalArgumentException();
}
}
static class S extends ScaleGestureDetector.SimpleOnScaleGestureListener {
private ScaleGestureDetector.OnScaleGestureListener mListener;
void setRealGestureDetector(ScaleGestureDetector.OnScaleGestureListener l) {
mListener = l;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
return mListener.onScale(detector);
}
}
private class PinchToZoomGestureDetector extends ScaleGestureDetector
implements ScaleGestureDetector.OnScaleGestureListener {
PinchToZoomGestureDetector(Context context) {
this(context, new S());
}
PinchToZoomGestureDetector(Context context, S s) {
super(context, s);
s.setRealGestureDetector(this);
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scale = detector.getScaleFactor();
// Speeding up the zoom by 2X.
if (scale > 1f) {
scale = 1.0f + (scale - 1.0f) * 2;
} else {
scale = 1.0f - (1.0f - scale) * 2;
}
float newRatio = getZoomRatio() * scale;
newRatio = rangeLimit(newRatio, getMaxZoomRatio(), getMinZoomRatio());
setZoomRatio(newRatio);
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
}
}
}
@@ -0,0 +1,696 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.camera.view;
import android.Manifest.permission;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.util.Rational;
import android.util.Size;
import androidx.annotation.NonNull;
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.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.utils.CameraOrientationUtil;
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.camera.lifecycle.ProcessCameraProvider;
import androidx.core.util.Preconditions;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.OnLifecycleEvent;
import com.google.common.util.concurrent.ListenableFuture;
import org.thoughtcrime.securesms.mediasend.camerax.CameraXUtil;
import org.thoughtcrime.securesms.mms.MediaConstraints;
import org.thoughtcrime.securesms.video.VideoUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import static androidx.camera.core.ImageCapture.FLASH_MODE_OFF;
/** CameraX use case operation built on @{link androidx.camera.core}. */
@RequiresApi(21)
@SuppressLint("RestrictedApi")
final class SignalCameraXModule {
public static final String TAG = "CameraXModule";
private static final float UNITY_ZOOM_SCALE = 1f;
private static final float ZOOM_NOT_SUPPORTED = UNITY_ZOOM_SCALE;
private static final Rational ASPECT_RATIO_16_9 = new Rational(16, 9);
private static final Rational ASPECT_RATIO_4_3 = new Rational(4, 3);
private static final Rational ASPECT_RATIO_9_16 = new Rational(9, 16);
private static final Rational ASPECT_RATIO_3_4 = new Rational(3, 4);
private final Preview.Builder mPreviewBuilder;
private final VideoCapture.Builder mVideoCaptureBuilder;
private final ImageCapture.Builder mImageCaptureBuilder;
private final SignalCameraView mCameraView;
final AtomicBoolean mVideoIsRecording = new AtomicBoolean(false);
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
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
Camera mCamera;
@Nullable
private ImageCapture mImageCapture;
@Nullable
private VideoCapture mVideoCapture;
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
@Nullable
Preview mPreview;
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
@Nullable
LifecycleOwner mCurrentLifecycle;
private final LifecycleObserver mCurrentLifecycleObserver =
new LifecycleObserver() {
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onDestroy(LifecycleOwner owner) {
if (owner == mCurrentLifecycle) {
clearCurrentLifecycle();
}
}
};
@Nullable
private LifecycleOwner mNewLifecycle;
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
@Nullable
Integer mCameraLensFacing = CameraSelector.LENS_FACING_BACK;
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
@Nullable
ProcessCameraProvider mCameraProvider;
SignalCameraXModule(SignalCameraView view) {
mCameraView = view;
Futures.addCallback(ProcessCameraProvider.getInstance(view.getContext()),
new FutureCallback<ProcessCameraProvider>() {
// TODO(b/124269166): Rethink how we can handle permissions here.
@SuppressLint("MissingPermission")
@Override
public void onSuccess(@Nullable ProcessCameraProvider provider) {
Preconditions.checkNotNull(provider);
mCameraProvider = provider;
if (mCurrentLifecycle != null) {
bindToLifecycle(mCurrentLifecycle);
}
}
@Override
public void onFailure(Throwable t) {
throw new RuntimeException("CameraX failed to initialize.", t);
}
}, CameraXExecutors.mainThreadExecutor());
mPreviewBuilder = new Preview.Builder().setTargetName("Preview");
mImageCaptureBuilder = new ImageCapture.Builder().setTargetName("ImageCapture");
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;
if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0) {
bindToLifecycleAfterViewMeasured();
}
}
@RequiresPermission(permission.CAMERA)
void bindToLifecycleAfterViewMeasured() {
if (mNewLifecycle == null) {
return;
}
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 (mCameraProvider == null) {
// try again once the camera provider is no longer null
return;
}
Set<Integer> available = getAvailableCameraLensFacing();
if (available.isEmpty()) {
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)) {
Logger.w(TAG, "Camera does not exist with direction " + mCameraLensFacing);
// Default to the first available camera direction
mCameraLensFacing = available.iterator().next();
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
// the user explicitly sets the LensFacing to null, or if we determined there
// were no available cameras, which should be logged in the logic above.
if (mCameraLensFacing == null) {
return;
}
// Set the preferred aspect ratio as 4:3 if it is IMAGE only mode. Set the preferred aspect
// ratio as 16:9 if it is VIDEO or MIXED mode. Then, it will be WYSIWYG when the view finder
// is in CENTER_INSIDE mode.
boolean isDisplayPortrait = getDisplayRotationDegrees() == 0
|| getDisplayRotationDegrees() == 180;
// Begin Signal Custom Code Block
int resolution = CameraXUtil.getIdealResolution(Resources.getSystem().getDisplayMetrics().widthPixels, Resources.getSystem().getDisplayMetrics().heightPixels);
// End Signal Custom Code Block
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
targetAspectRatio = isDisplayPortrait ? ASPECT_RATIO_3_4 : ASPECT_RATIO_4_3;
} else {
// Begin Signal Custom Code Block
mImageCaptureBuilder.setTargetResolution(CameraXUtil.buildResolutionForRatio(resolution, ASPECT_RATIO_16_9, isDisplayPortrait));
// End Signal Custom Code Block
targetAspectRatio = isDisplayPortrait ? ASPECT_RATIO_9_16 : ASPECT_RATIO_16_9;
}
// Begin Signal Custom Code Block
mImageCaptureBuilder.setCaptureMode(CameraXUtil.getOptimalCaptureMode());
// End Signal Custom Code Block
mImageCaptureBuilder.setTargetRotation(getDisplaySurfaceRotation());
mImageCapture = mImageCaptureBuilder.build();
// Begin Signal Custom Code Block
Size size = VideoUtil.getVideoRecordingSize();
mVideoCaptureBuilder.setTargetResolution(size);
mVideoCaptureBuilder.setMaxResolution(size);
// End Signal Custom Code Block
mVideoCaptureBuilder.setTargetRotation(getDisplaySurfaceRotation());
// Begin Signal Custom Code Block
if (MediaConstraints.isVideoTranscodeAvailable()) {
mVideoCapture = mVideoCaptureBuilder.build();
}
// End Signal Custom Code Block
// Adjusts the preview resolution according to the view size and the target aspect ratio.
int height = (int) (getMeasuredWidth() / targetAspectRatio.floatValue());
mPreviewBuilder.setTargetResolution(new Size(getMeasuredWidth(), height));
mPreview = mPreviewBuilder.build();
mPreview.setSurfaceProvider(mCameraView.getPreviewView().getSurfaceProvider());
CameraSelector cameraSelector =
new CameraSelector.Builder().requireLensFacing(mCameraLensFacing).build();
if (getCaptureMode() == SignalCameraView.CaptureMode.IMAGE) {
mCamera = mCameraProvider.bindToLifecycle(mCurrentLifecycle, cameraSelector,
mImageCapture,
mPreview);
} else if (getCaptureMode() == SignalCameraView.CaptureMode.VIDEO) {
mCamera = mCameraProvider.bindToLifecycle(mCurrentLifecycle, cameraSelector,
mVideoCapture,
mPreview);
} else {
mCamera = mCameraProvider.bindToLifecycle(mCurrentLifecycle, cameraSelector,
mImageCapture,
mVideoCapture, mPreview);
}
setZoomRatio(UNITY_ZOOM_SCALE);
mCurrentLifecycle.getLifecycle().addObserver(mCurrentLifecycleObserver);
// Enable flash setting in ImageCapture after use cases are created and binded.
setFlash(getFlash());
}
public void open() {
throw new UnsupportedOperationException(
"Explicit open/close of camera not yet supported. Use bindtoLifecycle() instead.");
}
public void close() {
throw new UnsupportedOperationException(
"Explicit open/close of camera not yet supported. Use bindtoLifecycle() instead.");
}
public void takePicture(Executor executor, OnImageCapturedCallback 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("OnImageCapturedCallback should not be empty");
}
mImageCapture.takePicture(executor, 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() == SignalCameraView.CaptureMode.IMAGE) {
throw new IllegalStateException("Can not record video under IMAGE capture mode.");
}
if (callback == null) {
throw new IllegalArgumentException("OnVideoSavedCallback should not be empty");
}
mVideoIsRecording.set(true);
mVideoCapture.startRecording(
outputFileOptions,
executor,
new VideoCapture.OnVideoSavedCallback() {
@Override
public void onVideoSaved(
@NonNull VideoCapture.OutputFileResults outputFileResults) {
mVideoIsRecording.set(false);
callback.onVideoSaved(outputFileResults);
}
@Override
public void onError(
@VideoCapture.VideoCaptureError int videoCaptureError,
@NonNull String message,
@Nullable Throwable cause) {
mVideoIsRecording.set(false);
Logger.e(TAG, message, cause);
callback.onError(videoCaptureError, message, cause);
}
});
}
public void stopRecording() {
if (mVideoCapture == null) {
return;
}
mVideoCapture.stopRecording();
}
public boolean isRecording() {
return mVideoIsRecording.get();
}
// TODO(b/124269166): Rethink how we can handle permissions here.
@SuppressLint("MissingPermission")
public void setCameraLensFacing(@Nullable Integer lensFacing) {
// Setting same lens facing is a no-op, so check for that first
if (!Objects.equals(mCameraLensFacing, lensFacing)) {
// If we're not bound to a lifecycle, just update the camera that will be opened when we
// attach to a lifecycle.
mCameraLensFacing = lensFacing;
if (mCurrentLifecycle != null) {
// Re-bind to lifecycle with new camera
bindToLifecycle(mCurrentLifecycle);
}
}
}
@RequiresPermission(permission.CAMERA)
public boolean hasCameraWithLensFacing(@CameraSelector.LensFacing int lensFacing) {
if (mCameraProvider == null) {
return false;
}
try {
return mCameraProvider.hasCamera(
new CameraSelector.Builder().requireLensFacing(lensFacing).build());
} catch (CameraInfoUnavailableException e) {
return false;
}
}
@Nullable
public Integer getLensFacing() {
return mCameraLensFacing;
}
public void toggleCamera() {
// TODO(b/124269166): Rethink how we can handle permissions here.
@SuppressLint("MissingPermission")
Set<Integer> availableCameraLensFacing = getAvailableCameraLensFacing();
if (availableCameraLensFacing.isEmpty()) {
return;
}
if (mCameraLensFacing == null) {
setCameraLensFacing(availableCameraLensFacing.iterator().next());
return;
}
if (mCameraLensFacing == CameraSelector.LENS_FACING_BACK
&& availableCameraLensFacing.contains(CameraSelector.LENS_FACING_FRONT)) {
setCameraLensFacing(CameraSelector.LENS_FACING_FRONT);
return;
}
if (mCameraLensFacing == CameraSelector.LENS_FACING_FRONT
&& availableCameraLensFacing.contains(CameraSelector.LENS_FACING_BACK)) {
setCameraLensFacing(CameraSelector.LENS_FACING_BACK);
return;
}
}
public float getZoomRatio() {
if (mCamera != null) {
return mCamera.getCameraInfo().getZoomState().getValue().getZoomRatio();
} else {
return UNITY_ZOOM_SCALE;
}
}
public void setZoomRatio(float zoomRatio) {
if (mCamera != null) {
ListenableFuture<Void> future = mCamera.getCameraControl().setZoomRatio(
zoomRatio);
Futures.addCallback(future, new FutureCallback<Void>() {
@Override
public void onSuccess(@Nullable Void result) {
}
@Override
public void onFailure(Throwable t) {
// Throw the unexpected error.
throw new RuntimeException(t);
}
}, CameraXExecutors.directExecutor());
} else {
Logger.e(TAG, "Failed to set zoom ratio");
}
}
public float getMinZoomRatio() {
if (mCamera != null) {
return mCamera.getCameraInfo().getZoomState().getValue().getMinZoomRatio();
} else {
return UNITY_ZOOM_SCALE;
}
}
public float getMaxZoomRatio() {
if (mCamera != null) {
return mCamera.getCameraInfo().getZoomState().getValue().getMaxZoomRatio();
} else {
return ZOOM_NOT_SUPPORTED;
}
}
public boolean isZoomSupported() {
return getMaxZoomRatio() != ZOOM_NOT_SUPPORTED;
}
// TODO(b/124269166): Rethink how we can handle permissions here.
@SuppressLint("MissingPermission")
private void rebindToLifecycle() {
if (mCurrentLifecycle != null) {
bindToLifecycle(mCurrentLifecycle);
}
}
boolean isBoundToLifecycle() {
return mCamera != null;
}
int getRelativeCameraOrientation(boolean compensateForMirroring) {
int rotationDegrees = 0;
if (mCamera != null) {
rotationDegrees =
mCamera.getCameraInfo().getSensorRotationDegrees(getDisplaySurfaceRotation());
if (compensateForMirroring) {
rotationDegrees = (360 - rotationDegrees) % 360;
}
}
return rotationDegrees;
}
public void invalidateView() {
updateViewInfo();
}
void clearCurrentLifecycle() {
if (mCurrentLifecycle != null && mCameraProvider != null) {
// Remove previous use cases
List<UseCase> toUnbind = new ArrayList<>();
if (mImageCapture != null && mCameraProvider.isBound(mImageCapture)) {
toUnbind.add(mImageCapture);
}
if (mVideoCapture != null && mCameraProvider.isBound(mVideoCapture)) {
toUnbind.add(mVideoCapture);
}
if (mPreview != null && mCameraProvider.isBound(mPreview)) {
toUnbind.add(mPreview);
}
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;
}
// Update view related information used in use cases
private void updateViewInfo() {
if (mImageCapture != null) {
mImageCapture.setCropAspectRatio(new Rational(getWidth(), getHeight()));
mImageCapture.setTargetRotation(getDisplaySurfaceRotation());
}
if (mVideoCapture != null) {
mVideoCapture.setTargetRotation(getDisplaySurfaceRotation());
}
}
@RequiresPermission(permission.CAMERA)
private Set<Integer> getAvailableCameraLensFacing() {
// Start with all camera directions
Set<Integer> available = new LinkedHashSet<>(Arrays.asList(LensFacingConverter.values()));
// If we're bound to a lifecycle, remove unavailable cameras
if (mCurrentLifecycle != null) {
if (!hasCameraWithLensFacing(CameraSelector.LENS_FACING_BACK)) {
available.remove(CameraSelector.LENS_FACING_BACK);
}
if (!hasCameraWithLensFacing(CameraSelector.LENS_FACING_FRONT)) {
available.remove(CameraSelector.LENS_FACING_FRONT);
}
}
return available;
}
@ImageCapture.FlashMode
public int getFlash() {
return mFlash;
}
// Begin Signal Custom Code Block
public boolean hasFlash() {
if (mImageCapture == null) {
return false;
}
CameraInternal camera = mImageCapture.getCamera();
if (camera == null) {
return false;
}
return camera.getCameraInfoInternal().hasFlashUnit();
}
// End Signal Custom Code Block
public void setFlash(@ImageCapture.FlashMode int flash) {
this.mFlash = flash;
if (mImageCapture == null) {
// Do nothing if there is no imageCapture
return;
}
mImageCapture.setFlashMode(flash);
}
public void enableTorch(boolean torch) {
if (mCamera == null) {
return;
}
ListenableFuture<Void> future = mCamera.getCameraControl().enableTorch(torch);
Futures.addCallback(future, new FutureCallback<Void>() {
@Override
public void onSuccess(@Nullable Void result) {
}
@Override
public void onFailure(Throwable t) {
// Throw the unexpected error.
throw new RuntimeException(t);
}
}, CameraXExecutors.directExecutor());
}
public boolean isTorchOn() {
if (mCamera == null) {
return false;
}
return mCamera.getCameraInfo().getTorchState().getValue() == TorchState.ON;
}
public Context getContext() {
return mCameraView.getContext();
}
public int getWidth() {
return mCameraView.getWidth();
}
public int getHeight() {
return mCameraView.getHeight();
}
public int getDisplayRotationDegrees() {
return CameraOrientationUtil.surfaceRotationToDegrees(getDisplaySurfaceRotation());
}
protected int getDisplaySurfaceRotation() {
return mCameraView.getDisplaySurfaceRotation();
}
private int getMeasuredWidth() {
return mCameraView.getMeasuredWidth();
}
private int getMeasuredHeight() {
return mCameraView.getMeasuredHeight();
}
@Nullable
public Camera getCamera() {
return mCamera;
}
@NonNull
public SignalCameraView.CaptureMode getCaptureMode() {
return mCaptureMode;
}
public void setCaptureMode(@NonNull SignalCameraView.CaptureMode captureMode) {
this.mCaptureMode = captureMode;
rebindToLifecycle();
}
public long getMaxVideoDuration() {
return mMaxVideoDuration;
}
public void setMaxVideoDuration(long duration) {
mMaxVideoDuration = duration;
}
public long getMaxVideoSize() {
return mMaxVideoSize;
}
public void setMaxVideoSize(long size) {
mMaxVideoSize = size;
}
public boolean isPaused() {
return false;
}
}
@@ -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) { }
};
}
}
@@ -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;
}
}
@@ -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);
}
}
@@ -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();
}
}
@@ -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);
}
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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字节 指定数据块中数据域的长度,其长度不超过(231-1)字节
* 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 {
}
}
@@ -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();
}
}
@@ -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();
}
}
@@ -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");
}
@@ -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");
}
@@ -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);
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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);
}
}
@@ -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();
}
}
@@ -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);
}
@@ -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;
}
}
@@ -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();
}
}
@@ -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());
}
}
@@ -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();
}
}
@@ -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));
}
}
@@ -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();
}
}
@@ -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;
}
@@ -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;
}
}
@@ -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;
}
@@ -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);
}
}
@@ -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());
}
}
@@ -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);
}
}
@@ -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;
}
@@ -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);
}
}
@@ -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());
}
}
@@ -1,20 +1,22 @@
package org.thoughtcrime.securesms; package org.thoughtcrime.securesms;
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile; import org.thoughtcrime.securesms.util.FeatureFlags;
import org.whispersystems.signalservice.api.account.AccountAttributes;
public final class AppCapabilities { public final class AppCapabilities {
private AppCapabilities() { private AppCapabilities() {
} }
private static final boolean UUID_CAPABLE = false; private static final boolean UUID_CAPABLE = false;
private static final boolean GROUPS_V2_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 * @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. * asking if the user has set a Signal PIN or not.
*/ */
public static SignalServiceProfile.Capabilities getCapabilities(boolean storageCapable) { public static AccountAttributes.Capabilities getCapabilities(boolean storageCapable) {
return new SignalServiceProfile.Capabilities(UUID_CAPABLE, GROUPS_V2_CAPABLE, storageCapable); return new AccountAttributes.Capabilities(UUID_CAPABLE, GV2_CAPABLE, storageCapable, GV1_MIGRATION, FeatureFlags.senderKey());
} }
} }
@@ -4,12 +4,13 @@ import android.content.Context;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.insights.InsightsOptOut; import org.thoughtcrime.securesms.insights.InsightsOptOut;
import org.thoughtcrime.securesms.jobmanager.JobManager; import org.thoughtcrime.securesms.jobmanager.JobManager;
import org.thoughtcrime.securesms.jobs.EmojiSearchIndexDownloadJob;
import org.thoughtcrime.securesms.jobs.StickerPackDownloadJob; import org.thoughtcrime.securesms.jobs.StickerPackDownloadJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.migrations.ApplicationMigrations; import org.thoughtcrime.securesms.migrations.ApplicationMigrations;
import org.thoughtcrime.securesms.stickers.BlessedPacks; import org.thoughtcrime.securesms.stickers.BlessedPacks;
import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.TextSecurePreferences;
@@ -34,10 +35,16 @@ public final class AppInitialization {
TextSecurePreferences.setJobManagerVersion(context, JobManager.CURRENT_VERSION); TextSecurePreferences.setJobManagerVersion(context, JobManager.CURRENT_VERSION);
TextSecurePreferences.setLastExperienceVersionCode(context, Util.getCanonicalVersionCode()); TextSecurePreferences.setLastExperienceVersionCode(context, Util.getCanonicalVersionCode());
TextSecurePreferences.setHasSeenStickerIntroTooltip(context, true); 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(); ApplicationDependencies.getMegaphoneRepository().onFirstEverAppLaunch();
SignalStore.onFirstEverAppLaunch(); SignalStore.onFirstEverAppLaunch();
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forInstall(BlessedPacks.ZOZO.getPackId(), BlessedPacks.ZOZO.getPackKey(), false)); 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.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_HANDS.getPackId(), BlessedPacks.SWOON_HANDS.getPackKey()));
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forReference(BlessedPacks.SWOON_FACES.getPackId(), BlessedPacks.SWOON_FACES.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(); ApplicationDependencies.getMegaphoneRepository().onFirstEverAppLaunch();
SignalStore.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.ZOZO.getPackId(), BlessedPacks.ZOZO.getPackKey(), false));
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forInstall(BlessedPacks.BANDIT.getPackId(), BlessedPacks.BANDIT.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_HANDS.getPackId(), BlessedPacks.SWOON_HANDS.getPackKey()));
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forReference(BlessedPacks.SWOON_FACES.getPackId(), BlessedPacks.SWOON_FACES.getPackKey())); ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forReference(BlessedPacks.SWOON_FACES.getPackId(), BlessedPacks.SWOON_FACES.getPackKey()));
} }
@@ -16,70 +16,74 @@
*/ */
package org.thoughtcrime.securesms; package org.thoughtcrime.securesms;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import androidx.appcompat.app.AppCompatDelegate; import androidx.appcompat.app.AppCompatDelegate;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ProcessLifecycleOwner;
import androidx.multidex.MultiDexApplication; import androidx.multidex.MultiDexApplication;
import com.google.android.gms.security.ProviderInstaller; import com.google.android.gms.security.ProviderInstaller;
import org.conscrypt.Conscrypt; import org.conscrypt.Conscrypt;
import org.signal.aesgcmprovider.AesGcmProvider; 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.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.DatabaseFactory;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper; import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencyProvider; import org.thoughtcrime.securesms.dependencies.ApplicationDependencyProvider;
import org.thoughtcrime.securesms.emoji.EmojiSource;
import org.thoughtcrime.securesms.gcm.FcmJobService; import org.thoughtcrime.securesms.gcm.FcmJobService;
import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob; 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.FcmRefreshJob;
import org.thoughtcrime.securesms.jobs.GroupV1MigrationJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob; import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob; import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
import org.thoughtcrime.securesms.jobs.RefreshPreKeysJob; import org.thoughtcrime.securesms.jobs.RefreshPreKeysJob;
import org.thoughtcrime.securesms.logging.AndroidLogger; import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger; import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger;
import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.logging.LogSecretProvider;
import org.thoughtcrime.securesms.logging.PersistentLogger; import org.thoughtcrime.securesms.messageprocessingalarm.MessageProcessReceiver;
import org.thoughtcrime.securesms.logging.SignalUncaughtExceptionHandler;
import org.thoughtcrime.securesms.migrations.ApplicationMigrations; import org.thoughtcrime.securesms.migrations.ApplicationMigrations;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.notifications.NotificationChannels; import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.providers.BlobProvider; import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess; import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.ratelimit.RateLimitUtil;
import org.thoughtcrime.securesms.registration.RegistrationUtil; import org.thoughtcrime.securesms.registration.RegistrationUtil;
import org.thoughtcrime.securesms.revealable.ViewOnceMessageManager;
import org.thoughtcrime.securesms.ringrtc.RingRtcLogger; import org.thoughtcrime.securesms.ringrtc.RingRtcLogger;
import org.thoughtcrime.securesms.service.DirectoryRefreshListener; import org.thoughtcrime.securesms.service.DirectoryRefreshListener;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
import org.thoughtcrime.securesms.service.IncomingMessageObserver;
import org.thoughtcrime.securesms.service.KeyCachingService; import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.service.LocalBackupListener; import org.thoughtcrime.securesms.service.LocalBackupListener;
import org.thoughtcrime.securesms.service.RotateSenderCertificateListener; import org.thoughtcrime.securesms.service.RotateSenderCertificateListener;
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener; import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
import org.thoughtcrime.securesms.service.UpdateApkRefreshListener; import org.thoughtcrime.securesms.service.UpdateApkRefreshListener;
import org.thoughtcrime.securesms.storage.StorageSyncHelper; 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.FeatureFlags;
import org.thoughtcrime.securesms.util.PlayServicesUtil; import org.thoughtcrime.securesms.util.SignalUncaughtExceptionHandler;
import org.thoughtcrime.securesms.util.TextSecurePreferences; 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.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageContextWrapper;
import org.webrtc.voiceengine.WebRtcAudioManager; import org.webrtc.voiceengine.WebRtcAudioManager;
import org.webrtc.voiceengine.WebRtcAudioUtils; import org.webrtc.voiceengine.WebRtcAudioUtils;
import org.whispersystems.libsignal.logging.SignalProtocolLoggerProvider; import org.whispersystems.libsignal.logging.SignalProtocolLoggerProvider;
import java.security.Security; import java.security.Security;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
@@ -90,18 +94,11 @@ import java.util.concurrent.TimeUnit;
* *
* @author Moxie Marlinspike * @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 PersistentLogger persistentLogger;
private ViewOnceMessageManager viewOnceMessageManager;
private TypingStatusRepository typingStatusRepository;
private TypingStatusSender typingStatusSender;
private IncomingMessageObserver incomingMessageObserver;
private PersistentLogger persistentLogger;
private volatile boolean isAppVisible;
public static ApplicationContext getInstance(Context context) { public static ApplicationContext getInstance(Context context) {
return (ApplicationContext)context.getApplicationContext(); return (ApplicationContext)context.getApplicationContext();
@@ -109,88 +106,113 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); Tracer.getInstance().start("Application#onCreate()");
Log.i(TAG, "onCreate()"); AppStartup.getInstance().onApplicationCreate();
initializeSecurityProvider();
initializeLogging();
initializeCrashHandling();
initializeAppDependencies();
initializeFirstEverAppLaunch();
initializeApplicationMigrations();
initializeMessageRetrieval();
initializeExpiringMessageManager();
initializeRevealableMessageManager();
initializeTypingStatusRepository();
initializeTypingStatusSender();
initializeGcmCheck();
initializeSignedPreKeyCheck();
initializePeriodicTasks();
initializeCircumvention();
initializeRingRtc();
initializePendingMessages();
initializeBlobProvider();
initializeCleanup();
initializePlayServicesCheck();
FeatureFlags.init(); long startTime = System.currentTimeMillis();
NotificationChannels.create(this);
RefreshPreKeysJob.scheduleIfNecessary();
StorageSyncHelper.scheduleRoutineSync();
RegistrationUtil.markRegistrationPossiblyComplete();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
if (Build.VERSION.SDK_INT < 21) { if (FeatureFlags.internalUser()) {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); 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("eat-db", () -> DatabaseFactory.getInstance(this))
.addBlocking("app-dependencies", this::initializeAppDependencies)
.addBlocking("notification-channels", () -> NotificationChannels.create(this))
.addBlocking("first-launch", this::initializeFirstEverAppLaunch)
.addBlocking("app-migrations", this::initializeApplicationMigrations)
.addBlocking("ring-rtc", this::initializeRingRtc)
.addBlocking("mark-registration", () -> RegistrationUtil.maybeMarkRegistrationComplete(this))
.addBlocking("lifecycle-observer", () -> ApplicationDependencies.getAppForegroundObserver().addListener(this))
.addBlocking("message-retriever", this::initializeMessageRetrieval)
.addBlocking("dynamic-theme", () -> DynamicTheme.setDefaultDayNightMode(this))
.addBlocking("vector-compat", () -> {
if (Build.VERSION.SDK_INT < 21) {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
})
.addBlocking("proxy-init", () -> {
if (SignalStore.proxy().isProxyEnabled()) {
Log.w(TAG, "Proxy detected. Enabling Conscrypt.setUseEngineSocketByDefault()");
Conscrypt.setUseEngineSocketByDefault(true);
}
})
.addBlocking("blob-provider", this::initializeBlobProvider)
.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 @Override
public void onStart(@NonNull LifecycleOwner owner) { public void onForeground() {
isAppVisible = true; long startTime = System.currentTimeMillis();
Log.i(TAG, "App is now visible."); Log.i(TAG, "App is now visible.");
FeatureFlags.refreshIfNecessary();
ApplicationDependencies.getRecipientCache().warmUp();
executePendingContactSync();
KeyCachingService.onAppForegrounded(this);
ApplicationDependencies.getFrameRateTracker().begin(); ApplicationDependencies.getFrameRateTracker().begin();
ApplicationDependencies.getMegaphoneRepository().onAppForegrounded(); 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 @Override
public void onStop(@NonNull LifecycleOwner owner) { public void onBackground() {
isAppVisible = false;
Log.i(TAG, "App is no longer visible."); Log.i(TAG, "App is no longer visible.");
KeyCachingService.onAppBackgrounded(this); KeyCachingService.onAppBackgrounded(this);
MessageNotifier.setVisibleThread(-1); ApplicationDependencies.getMessageNotifier().clearVisibleThread();
ApplicationDependencies.getFrameRateTracker().end(); ApplicationDependencies.getFrameRateTracker().end();
} ApplicationDependencies.getShakeToReport().disable();
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;
} }
public PersistentLogger getPersistentLogger() { public PersistentLogger getPersistentLogger() {
return persistentLogger; return persistentLogger;
} }
public void checkBuildExpiration() {
if (Util.getTimeUntilBuildExpiry() <= 0 && !SignalStore.misc().isClientDeprecated()) {
Log.w(TAG, "Build expired!");
SignalStore.misc().markClientDeprecated();
}
}
private void initializeSecurityProvider() { private void initializeSecurityProvider() {
try { try {
Class.forName("org.signal.aesgcmprovider.AesGcmCipher"); Class.forName("org.signal.aesgcmprovider.AesGcmCipher");
@@ -216,8 +238,8 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
} }
private void initializeLogging() { private void initializeLogging() {
persistentLogger = new PersistentLogger(this); persistentLogger = new PersistentLogger(this, LogSecretProvider.getOrCreateAttachmentSecret(this), BuildConfig.VERSION_NAME, FeatureFlags.internalUser() ? 15 : 7, ByteUnit.KILOBYTES.toBytes(300));
org.thoughtcrime.securesms.logging.Log.initialize(new AndroidLogger(), persistentLogger); org.signal.core.util.logging.Log.initialize(FeatureFlags::internalUser, new AndroidLogger(), persistentLogger);
SignalProtocolLoggerProvider.setProvider(new CustomSignalProtocolLogger()); SignalProtocolLoggerProvider.setProvider(new CustomSignalProtocolLogger());
} }
@@ -232,22 +254,28 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
} }
public void initializeMessageRetrieval() { public void initializeMessageRetrieval() {
this.incomingMessageObserver = new IncomingMessageObserver(this); ApplicationDependencies.getIncomingMessageObserver();
} }
private void initializeAppDependencies() { private void initializeAppDependencies() {
ApplicationDependencies.init(this, new ApplicationDependencyProvider(this, new SignalServiceNetworkAccess(this))); ApplicationDependencies.init(this, new ApplicationDependencyProvider(this));
} }
private void initializeFirstEverAppLaunch() { private void initializeFirstEverAppLaunch() {
if (TextSecurePreferences.getFirstInstallVersion(this) == -1) { if (TextSecurePreferences.getFirstInstallVersion(this) == -1) {
if (!SQLCipherOpenHelper.databaseFileExists(this)) { if (!SQLCipherOpenHelper.databaseFileExists(this) || VersionTracker.getDaysSinceFirstInstalled(this) < 365) {
Log.i(TAG, "First ever app launch!"); Log.i(TAG, "First ever app launch!");
AppInitialization.onFirstEverAppLaunch(this); AppInitialization.onFirstEverAppLaunch(this);
} }
Log.i(TAG, "Setting first install version to " + BuildConfig.CANONICAL_VERSION_CODE); Log.i(TAG, "Setting first install version to " + BuildConfig.CANONICAL_VERSION_CODE);
TextSecurePreferences.setFirstInstallVersion(this, 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);
} }
} }
@@ -268,19 +296,15 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
} }
private void initializeExpiringMessageManager() { private void initializeExpiringMessageManager() {
this.expiringMessageManager = new ExpiringMessageManager(this); ApplicationDependencies.getExpiringMessageManager().checkSchedule();
} }
private void initializeRevealableMessageManager() { private void initializeRevealableMessageManager() {
this.viewOnceMessageManager = new ViewOnceMessageManager(this); ApplicationDependencies.getViewOnceMessageManager().scheduleIfNecessary();
} }
private void initializeTypingStatusRepository() { private void initializePendingRetryReceiptManager() {
this.typingStatusRepository = new TypingStatusRepository(); ApplicationDependencies.getPendingRetryReceiptManager().scheduleIfNecessary();
}
private void initializeTypingStatusSender() {
this.typingStatusSender = new TypingStatusSender(this);
} }
private void initializePeriodicTasks() { private void initializePeriodicTasks() {
@@ -288,6 +312,7 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
DirectoryRefreshListener.schedule(this); DirectoryRefreshListener.schedule(this);
LocalBackupListener.schedule(this); LocalBackupListener.schedule(this);
RotateSenderCertificateListener.schedule(this); RotateSenderCertificateListener.schedule(this);
MessageProcessReceiver.startOrUpdateAlarm(this);
if (BuildConfig.PLAY_STORE_DISABLED) { if (BuildConfig.PLAY_STORE_DISABLED) {
UpdateApkRefreshListener.schedule(this); UpdateApkRefreshListener.schedule(this);
@@ -296,31 +321,11 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
private void initializeRingRtc() { private void initializeRingRtc() {
try { try {
Set<String> HARDWARE_AEC_BLACKLIST = new HashSet<String>() {{ if (RtcDeviceLists.hardwareAECBlocked()) {
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)) {
WebRtcAudioUtils.setWebRtcBasedAcousticEchoCanceler(true); WebRtcAudioUtils.setWebRtcBasedAcousticEchoCanceler(true);
} }
if (!OPEN_SL_ES_WHITELIST.contains(Build.MODEL)) { if (!RtcDeviceLists.openSLESAllowed()) {
WebRtcAudioManager.setBlacklistDeviceForOpenSLESUsage(true); WebRtcAudioManager.setBlacklistDeviceForOpenSLESUsage(true);
} }
@@ -330,23 +335,15 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
} }
} }
@SuppressLint("StaticFieldLeak") @WorkerThread
private void initializeCircumvention() { private void initializeCircumvention() {
AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() { if (new SignalServiceNetworkAccess(ApplicationContext.this).isCensored(ApplicationContext.this)) {
@Override try {
protected Void doInBackground(Void... params) { ProviderInstaller.installIfNeeded(ApplicationContext.this);
if (new SignalServiceNetworkAccess(ApplicationContext.this).isCensored(ApplicationContext.this)) { } catch (Throwable t) {
try { Log.w(TAG, t);
ProviderInstaller.installIfNeeded(ApplicationContext.this);
} catch (Throwable t) {
Log.w(TAG, t);
}
}
return null;
} }
}; }
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
private void executePendingContactSync() { private void executePendingContactSync() {
@@ -361,43 +358,56 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
if (Build.VERSION.SDK_INT >= 26) { if (Build.VERSION.SDK_INT >= 26) {
FcmJobService.schedule(this); FcmJobService.schedule(this);
} else { } else {
ApplicationDependencies.getJobManager().add(new PushNotificationReceiveJob(this)); ApplicationDependencies.getJobManager().add(new PushNotificationReceiveJob());
} }
TextSecurePreferences.setNeedsMessagePull(this, false); TextSecurePreferences.setNeedsMessagePull(this, false);
} }
} }
@WorkerThread
private void initializeBlobProvider() { private void initializeBlobProvider() {
SignalExecutors.BOUNDED.execute(() -> { BlobProvider.getInstance().initialize(this);
BlobProvider.getInstance().onSessionStart(this);
});
} }
@WorkerThread
private void initializeCleanup() { private void initializeCleanup() {
SignalExecutors.BOUNDED.execute(() -> { int deleted = DatabaseFactory.getAttachmentDatabase(this).deleteAbandonedPreuploadedAttachments();
int deleted = DatabaseFactory.getAttachmentDatabase(this).deleteAbandonedPreuploadedAttachments(); Log.i(TAG, "Deleted " + deleted + " abandoned attachments.");
Log.i(TAG, "Deleted " + deleted + " abandoned attachments.");
});
} }
private void initializePlayServicesCheck() { private void initializeGlideCodecs() {
if (TextSecurePreferences.isFcmDisabled(this)) { SignalGlideCodecs.setLogProvider(new org.signal.glide.Log.Provider() {
PlayServicesUtil.PlayServicesStatus status = PlayServicesUtil.getPlayServicesStatus(this); @Override
public void v(@NonNull String tag, @NonNull String message) {
if (status == PlayServicesUtil.PlayServicesStatus.SUCCESS) { Log.v(tag, message);
Log.i(TAG, "Play Services are newly-available. Updating to use FCM.");
TextSecurePreferences.setFcmDisabled(this, false);
ApplicationDependencies.getJobManager().startChain(new FcmRefreshJob())
.then(new RefreshAttributesJob())
.enqueue();
} }
}
@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 @Override
protected void attachBaseContext(Context base) { 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 { private static class ProviderInitializationException extends RuntimeException {
@@ -1,286 +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 PassphraseRequiredActionBarActivity
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) {
Intent intent = new Intent(preference.getContext(), EditProfileActivity.class);
intent.putExtra(EditProfileActivity.EXCLUDE_SYSTEM, true);
intent.putExtra(EditProfileActivity.DISPLAY_USERNAME, true);
intent.putExtra(EditProfileActivity.NEXT_BUTTON_TEXT, R.string.save);
requireActivity().startActivity(intent);
return true;
}
}
}
}
@@ -0,0 +1,142 @@
package org.thoughtcrime.securesms;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.transition.TransitionInflater;
import android.view.View;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityOptionsCompat;
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
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.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.
*/
public final class AvatarPreviewActivity extends PassphraseRequiredActivity {
private static final String TAG = Log.tag(AvatarPreviewActivity.class);
private static final String RECIPIENT_ID_EXTRA = "recipient_id";
public static @NonNull Intent intentFromRecipientId(@NonNull Context context,
@NonNull RecipientId recipientId)
{
Intent intent = new Intent(context, AvatarPreviewActivity.class);
intent.putExtra(RECIPIENT_ID_EXTRA, recipientId.serialize());
return intent;
}
public static Bundle createTransitionBundle(@NonNull Activity activity, @NonNull View from) {
return ActivityOptionsCompat.makeSceneTransitionAnimation(activity, from, "avatar").toBundle();
}
@Override
protected void onCreate(Bundle savedInstanceState, boolean ready) {
super.onCreate(savedInstanceState, ready);
setTheme(R.style.TextSecure_MediaPreview);
setContentView(R.layout.contact_photo_preview_activity);
if (Build.VERSION.SDK_INT >= 21) {
postponeEnterTransition();
TransitionInflater inflater = TransitionInflater.from(this);
getWindow().setSharedElementEnterTransition(inflater.inflateTransition(R.transition.full_screen_avatar_image_enter_transition_set));
getWindow().setSharedElementReturnTransition(inflater.inflateTransition(R.transition.full_screen_avatar_image_return_transition_set));
}
Toolbar toolbar = findViewById(R.id.toolbar);
ImageView avatar = findViewById(R.id.avatar);
setSupportActionBar(toolbar);
requireSupportActionBar().setDisplayHomeAsUpEnabled(true);
Context context = getApplicationContext();
RecipientId recipientId = RecipientId.from(getIntent().getStringExtra(RECIPIENT_ID_EXTRA));
Recipient.live(recipientId).observe(this, recipient -> {
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();
GlideApp.with(this)
.asBitmap()
.load(contactPhoto)
.fallback(fallbackPhoto.asCallCard(this))
.error(fallbackPhoto.asCallCard(this))
.diskCacheStrategy(DiskCacheStrategy.ALL)
.addListener(new RequestListener<Bitmap>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) {
Log.w(TAG, "Unable to load avatar, or avatar removed, closing");
finish();
return false;
}
@Override
public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
return false;
}
})
.into(new CustomTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
avatar.setImageDrawable(RoundedBitmapDrawableFactory.create(resources, resource));
if (Build.VERSION.SDK_INT >= 21) {
startPostponedEnterTransition();
}
}
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
}
});
toolbar.setTitle(recipient.getDisplayName(context));
});
FullscreenHelper fullscreenHelper = new FullscreenHelper(this);
findViewById(android.R.id.content).setOnClickListener(v -> fullscreenHelper.toggleUiVisibility());
fullscreenHelper.configureToolbarSpacer(findViewById(R.id.toolbar_cutout_spacer));
fullscreenHelper.showAndHideWithSystemUI(getWindow(), findViewById(R.id.toolbar_layout));
}
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
}
@@ -1,101 +0,0 @@
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.os.Bundle;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.app.ActivityOptionsCompat;
import androidx.appcompat.app.AppCompatActivity;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManager;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageActivityHelper;
import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageContextWrapper;
import java.lang.reflect.Field;
public abstract class BaseActionBarActivity extends AppCompatActivity {
private static final String TAG = BaseActionBarActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
if (BaseActivity.isMenuWorkaroundRequired()) {
forceOverflowMenu();
}
super.onCreate(savedInstanceState);
}
@Override
protected void onResume() {
super.onResume();
initializeScreenshotSecurity();
DynamicLanguageActivityHelper.recreateIfNotInCorrectLanguage(this, TextSecurePreferences.getLanguage(this));
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return (keyCode == KeyEvent.KEYCODE_MENU && BaseActivity.isMenuWorkaroundRequired()) || super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU && BaseActivity.isMenuWorkaroundRequired()) {
openOptionsMenu();
return true;
}
return super.onKeyUp(keyCode, event);
}
private void initializeScreenshotSecurity() {
if (TextSecurePreferences.isScreenSecurityEnabled(this)) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
} else {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
}
}
/**
* Modified from: http://stackoverflow.com/a/13098824
*/
private void forceOverflowMenu() {
try {
ViewConfiguration config = ViewConfiguration.get(this);
Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
if(menuKeyField != null) {
menuKeyField.setAccessible(true);
menuKeyField.setBoolean(config, false);
}
} catch (IllegalAccessException e) {
Log.w(TAG, "Failed to force overflow menu.");
} catch (NoSuchFieldException e) {
Log.w(TAG, "Failed to force overflow menu.");
}
}
protected void startActivitySceneTransition(Intent intent, View sharedView, String transitionName) {
Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(this, sharedView, transitionName)
.toBundle();
ActivityCompat.startActivity(this, intent, bundle);
}
@TargetApi(VERSION_CODES.LOLLIPOP)
protected void setStatusBarColor(int color) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(color);
}
}
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(DynamicLanguageContextWrapper.updateContext(newBase, TextSecurePreferences.getLanguage(newBase)));
}
}
@@ -1,46 +1,116 @@
package org.thoughtcrime.securesms; package org.thoughtcrime.securesms;
import android.content.Context; import android.content.Context;
import android.os.Build; import android.content.Intent;
import android.os.Build.VERSION; import android.content.res.Configuration;
import android.os.Build.VERSION_CODES; import android.os.Bundle;
import androidx.annotation.NonNull; import android.view.View;
import androidx.fragment.app.FragmentActivity; import android.view.WindowManager;
import android.view.KeyEvent;
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.TextSecurePreferences;
import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageActivityHelper;
import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageContextWrapper; import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageContextWrapper;
public abstract class BaseActivity extends FragmentActivity { import java.util.Objects;
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) { /**
return (keyCode == KeyEvent.KEYCODE_MENU && isMenuWorkaroundRequired()) || super.onKeyDown(keyCode, event); * Base class for all activities. The vast majority of activities shouldn't extend this directly.
} * Instead, they should extend {@link PassphraseRequiredActivity} so they're protected by
* screen lock.
*/
public abstract class BaseActivity extends AppCompatActivity {
private static final String TAG = Log.tag(BaseActivity.class);
@Override @Override
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) { protected void onCreate(Bundle savedInstanceState) {
if (keyCode == KeyEvent.KEYCODE_MENU && isMenuWorkaroundRequired()) { AppStartup.getInstance().onCriticalRenderEventStart();
openOptionsMenu(); logEvent("onCreate()");
return true; super.onCreate(savedInstanceState);
} AppStartup.getInstance().onCriticalRenderEventEnd();
return super.onKeyUp(keyCode, event);
}
public static boolean isMenuWorkaroundRequired() {
return VERSION.SDK_INT < VERSION_CODES.KITKAT &&
VERSION.SDK_INT > VERSION_CODES.GINGERBREAD_MR1 &&
("LGE".equalsIgnoreCase(Build.MANUFACTURER) || "E6710".equalsIgnoreCase(Build.DEVICE));
} }
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
DynamicLanguageActivityHelper.recreateIfNotInCorrectLanguage(this, TextSecurePreferences.getLanguage(this)); initializeScreenshotSecurity();
} }
@Override @Override
protected void attachBaseContext(Context newBase) { protected void onStart() {
super.attachBaseContext(DynamicLanguageContextWrapper.updateContext(newBase, TextSecurePreferences.getLanguage(newBase))); logEvent("onStart()");
ApplicationDependencies.getShakeToReport().registerActivity(this);
super.onStart();
}
@Override
protected void onStop() {
logEvent("onStop()");
super.onStop();
}
@Override
protected void onDestroy() {
logEvent("onDestroy()");
super.onDestroy();
}
private void initializeScreenshotSecurity() {
if (TextSecurePreferences.isScreenSecurityEnabled(this)) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
} else {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
}
}
protected void startActivitySceneTransition(Intent intent, View sharedView, String transitionName) {
Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(this, sharedView, transitionName)
.toBundle();
ActivityCompat.startActivity(this, intent, bundle);
}
@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
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);
}
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());
} }
} }
@@ -1,39 +1,61 @@
package org.thoughtcrime.securesms; package org.thoughtcrime.securesms;
import android.net.Uri;
import android.view.View;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import android.view.View; 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.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.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord; import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.database.model.ReactionRecord; 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.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.stickers.StickerLocator; import org.thoughtcrime.securesms.stickers.StickerLocator;
import org.thoughtcrime.securesms.video.exo.AttachmentMediaSourceFactory;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
public interface BindableConversationItem extends Unbindable { public interface BindableConversationItem extends Unbindable, GiphyMp4Playable, Colorizable {
void bind(@NonNull MessageRecord messageRecord, void bind(@NonNull LifecycleOwner lifecycleOwner,
@NonNull ConversationMessage messageRecord,
@NonNull Optional<MessageRecord> previousMessageRecord, @NonNull Optional<MessageRecord> previousMessageRecord,
@NonNull Optional<MessageRecord> nextMessageRecord, @NonNull Optional<MessageRecord> nextMessageRecord,
@NonNull GlideRequests glideRequests, @NonNull GlideRequests glideRequests,
@NonNull Locale locale, @NonNull Locale locale,
@NonNull Set<MessageRecord> batchSelected, @NonNull Set<ConversationMessage> batchSelected,
@NonNull Recipient recipients, @NonNull Recipient recipients,
@Nullable String searchQuery, @Nullable String searchQuery,
boolean pulseHighlight); boolean pulseMention,
boolean hasWallpaper,
boolean isMessageRequestAccepted,
@NonNull AttachmentMediaSourceFactory attachmentMediaSourceFactory,
boolean canPlayInline,
@NonNull Colorizer colorizer);
MessageRecord getMessageRecord(); ConversationMessage getConversationMessage();
void setEventListener(@Nullable EventListener listener); void setEventListener(@Nullable EventListener listener);
default void updateTimestamps() {
// Intentionally Blank.
}
interface EventListener { interface EventListener {
void onQuoteClicked(MmsMessageRecord messageRecord); void onQuoteClicked(MmsMessageRecord messageRecord);
void onLinkPreviewClicked(@NonNull LinkPreview linkPreview); void onLinkPreviewClicked(@NonNull LinkPreview linkPreview);
@@ -44,6 +66,27 @@ public interface BindableConversationItem extends Unbindable {
void onAddToContactsClicked(@NonNull Contact contact); void onAddToContactsClicked(@NonNull Contact contact);
void onMessageSharedContactClicked(@NonNull List<Recipient> choices); void onMessageSharedContactClicked(@NonNull List<Recipient> choices);
void onInviteSharedContactClicked(@NonNull List<Recipient> choices); void onInviteSharedContactClicked(@NonNull List<Recipient> choices);
void onReactionClicked(long messageId, boolean isMms); 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 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 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);
} }
} }
@@ -10,8 +10,11 @@ import java.util.Set;
public interface BindableConversationListItem extends Unbindable { public interface BindableConversationListItem extends Unbindable {
public void bind(@NonNull ThreadRecord thread, void bind(@NonNull ThreadRecord thread,
@NonNull GlideRequests glideRequests, @NonNull Locale locale, @NonNull GlideRequests glideRequests, @NonNull Locale locale,
@NonNull Set<Long> typingThreads, @NonNull Set<Long> typingThreads,
@NonNull Set<Long> selectedThreads, boolean batchMode); @NonNull Set<Long> selectedThreads, boolean batchMode);
void setBatchMode(boolean batchMode);
void updateTypingIndicator(@NonNull Set<Long> typingThreads);
} }
@@ -9,11 +9,10 @@ import androidx.annotation.WorkerThread;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.Lifecycle; import androidx.lifecycle.Lifecycle;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.recipients.Recipient; 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; import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
/** /**
@@ -33,15 +32,15 @@ public final class BlockUnblockDialog {
AlertDialog.Builder::show); AlertDialog.Builder::show);
} }
public static void showBlockAndDeleteFor(@NonNull Context context, public static void showBlockAndReportSpamFor(@NonNull Context context,
@NonNull Lifecycle lifecycle, @NonNull Lifecycle lifecycle,
@NonNull Recipient recipient, @NonNull Recipient recipient,
@NonNull Runnable onBlock, @NonNull Runnable onBlock,
@NonNull Runnable onBlockAndDelete) @NonNull Runnable onBlockAndReportSpam)
{ {
SimpleTask.run(lifecycle, SimpleTask.run(lifecycle,
() -> buildBlockFor(context, recipient, onBlock, onBlockAndDelete), () -> buildBlockFor(context, recipient, onBlock, onBlockAndReportSpam),
AlertDialog.Builder::show); AlertDialog.Builder::show);
} }
public static void showUnblockFor(@NonNull Context context, public static void showUnblockFor(@NonNull Context context,
@@ -58,11 +57,11 @@ public final class BlockUnblockDialog {
private static AlertDialog.Builder buildBlockFor(@NonNull Context context, private static AlertDialog.Builder buildBlockFor(@NonNull Context context,
@NonNull Recipient recipient, @NonNull Recipient recipient,
@NonNull Runnable onBlock, @NonNull Runnable onBlock,
@Nullable Runnable onBlockAndDelete) @Nullable Runnable onBlockAndReportSpam)
{ {
recipient = recipient.resolve(); recipient = recipient.resolve();
AlertDialog.Builder builder = new AlertDialog.Builder(context); AlertDialog.Builder builder = new MaterialAlertDialogBuilder(context);
Resources resources = context.getResources(); Resources resources = context.getResources();
if (recipient.isGroup()) { if (recipient.isGroup()) {
@@ -81,10 +80,10 @@ public final class BlockUnblockDialog {
builder.setTitle(resources.getString(R.string.BlockUnblockDialog_block_s, recipient.getDisplayName(context))); 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); 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.setNeutralButton(android.R.string.cancel, null);
builder.setPositiveButton(R.string.BlockUnblockDialog_block_and_delete, (d, w) -> onBlockAndDelete.run()); builder.setNegativeButton(R.string.BlockUnblockDialog_report_spam_and_block, (d, w) -> onBlockAndReportSpam.run());
builder.setNegativeButton(R.string.BlockUnblockDialog_block, (d, w) -> onBlock.run()); builder.setPositiveButton(R.string.BlockUnblockDialog_block, (d, w) -> onBlock.run());
} else { } else {
builder.setPositiveButton(R.string.BlockUnblockDialog_block, ((dialog, which) -> onBlock.run())); builder.setPositiveButton(R.string.BlockUnblockDialog_block, ((dialog, which) -> onBlock.run()));
builder.setNegativeButton(android.R.string.cancel, null); builder.setNegativeButton(android.R.string.cancel, null);
@@ -101,7 +100,7 @@ public final class BlockUnblockDialog {
{ {
recipient = recipient.resolve(); recipient = recipient.resolve();
AlertDialog.Builder builder = new AlertDialog.Builder(context); AlertDialog.Builder builder = new MaterialAlertDialogBuilder(context);
Resources resources = context.getResources(); Resources resources = context.getResources();
if (recipient.isGroup()) { if (recipient.isGroup()) {
@@ -1,140 +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.MenuItem;
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 PassphraseRequiredActionBarActivity {
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);
}
}
}
}
@@ -0,0 +1,48 @@
package org.thoughtcrime.securesms;
import android.app.Activity;
import android.content.Intent;
import android.view.ContextThemeWrapper;
import androidx.appcompat.app.AlertDialog;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.util.DynamicTheme;
public final class ClearAvatarPromptActivity extends Activity {
private static final String ARG_TITLE = "arg_title";
public static Intent createForUserProfilePhoto() {
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(ApplicationDependencies.getApplication(), ClearAvatarPromptActivity.class);
intent.putExtra(ARG_TITLE, R.string.ClearProfileActivity_remove_group_photo);
return intent;
}
@Override
public void onResume() {
super.onResume();
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(message)
.setNegativeButton(android.R.string.cancel, (dialog, which) -> finish())
.setPositiveButton(R.string.ClearProfileActivity_remove, (dialog, which) -> {
Intent result = new Intent();
result.putExtra("delete", true);
setResult(Activity.RESULT_OK, result);
finish();
})
.setOnCancelListener(dialog -> finish())
.show();
}
}
@@ -1,26 +0,0 @@
package org.thoughtcrime.securesms;
import android.app.Activity;
import android.content.Intent;
import androidx.appcompat.app.AlertDialog;
public class ClearProfileAvatarActivity extends Activity {
@Override
public void onResume() {
super.onResume();
new AlertDialog.Builder(this)
.setTitle(R.string.ClearProfileActivity_remove_profile_photo)
.setNegativeButton(android.R.string.cancel, (dialog, which) -> finish())
.setPositiveButton(R.string.ClearProfileActivity_remove, (dialog, which) -> {
Intent result = new Intent();
result.putExtra("delete", true);
setResult(Activity.RESULT_OK, result);
finish();
})
.show();
}
}
@@ -3,7 +3,6 @@ package org.thoughtcrime.securesms;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.database.Cursor;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.text.SpannableString; import android.text.SpannableString;
import android.text.Spanned; import android.text.Spanned;
@@ -12,12 +11,11 @@ import android.widget.TextView;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.crypto.ReentrantSessionLock;
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore; import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MmsDatabase; import org.thoughtcrime.securesms.database.MessageDatabase;
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.PushDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch; import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
@@ -30,17 +28,16 @@ import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.VerifySpan; import org.thoughtcrime.securesms.util.VerifySpan;
import org.whispersystems.libsignal.SignalProtocolAddress; import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalSessionLock;
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope; import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos; import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
import java.io.IOException; import java.io.IOException;
import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
public class ConfirmIdentityDialog extends AlertDialog { public class ConfirmIdentityDialog extends AlertDialog {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static final String TAG = ConfirmIdentityDialog.class.getSimpleName(); private static final String TAG = Log.tag(ConfirmIdentityDialog.class);
private OnClickListener callback; private OnClickListener callback;
@@ -51,7 +48,7 @@ public class ConfirmIdentityDialog extends AlertDialog {
super(context); super(context);
Recipient recipient = Recipient.resolved(mismatch.getRecipientId(context)); Recipient recipient = Recipient.resolved(mismatch.getRecipientId(context));
String name = recipient.toShortString(context); String name = recipient.getDisplayName(context);
String introduction = context.getString(R.string.ConfirmIdentityDialog_your_safety_number_with_s_has_changed, name, name); String introduction = context.getString(R.string.ConfirmIdentityDialog_your_safety_number_with_s_has_changed, name, name);
SpannableString spannableString = new SpannableString(introduction + " " + SpannableString spannableString = new SpannableString(introduction + " " +
context.getString(R.string.ConfirmIdentityDialog_you_may_wish_to_verify_your_safety_number_with_this_contact)); context.getString(R.string.ConfirmIdentityDialog_you_may_wish_to_verify_your_safety_number_with_this_contact));
@@ -97,7 +94,7 @@ public class ConfirmIdentityDialog extends AlertDialog {
{ {
@Override @Override
protected Void doInBackground(Void... params) { protected Void doInBackground(Void... params) {
synchronized (SESSION_LOCK) { try (SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
SignalProtocolAddress mismatchAddress = new SignalProtocolAddress(Recipient.resolved(recipientId).requireServiceId(), 1); SignalProtocolAddress mismatchAddress = new SignalProtocolAddress(Recipient.resolved(recipientId).requireServiceId(), 1);
TextSecureIdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(getContext()); TextSecureIdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(getContext());
@@ -105,7 +102,6 @@ public class ConfirmIdentityDialog extends AlertDialog {
} }
processMessageRecord(messageRecord); processMessageRecord(messageRecord);
processPendingMessageRecords(messageRecord.getThreadId(), mismatch);
return null; return null;
} }
@@ -115,29 +111,9 @@ public class ConfirmIdentityDialog extends AlertDialog {
else processIncomingMessageRecord(messageRecord); else processIncomingMessageRecord(messageRecord);
} }
private void processPendingMessageRecords(long threadId, IdentityKeyMismatch mismatch) {
MmsSmsDatabase mmsSmsDatabase = DatabaseFactory.getMmsSmsDatabase(getContext());
Cursor cursor = mmsSmsDatabase.getIdentityConflictMessagesForThread(threadId);
MmsSmsDatabase.Reader reader = mmsSmsDatabase.readerFor(cursor);
MessageRecord record;
try {
while ((record = reader.getNext()) != null) {
for (IdentityKeyMismatch recordMismatch : record.getIdentityKeyMismatches()) {
if (mismatch.equals(recordMismatch)) {
processMessageRecord(record);
}
}
}
} finally {
if (reader != null)
reader.close();
}
}
private void processOutgoingMessageRecord(MessageRecord messageRecord) { private void processOutgoingMessageRecord(MessageRecord messageRecord) {
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(getContext()); MessageDatabase smsDatabase = DatabaseFactory.getSmsDatabase(getContext());
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(getContext()); MessageDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(getContext());
if (messageRecord.isMms()) { if (messageRecord.isMms()) {
mmsDatabase.removeMismatchedIdentity(messageRecord.getId(), mmsDatabase.removeMismatchedIdentity(messageRecord.getId(),
@@ -160,8 +136,7 @@ public class ConfirmIdentityDialog extends AlertDialog {
private void processIncomingMessageRecord(MessageRecord messageRecord) { private void processIncomingMessageRecord(MessageRecord messageRecord) {
try { try {
PushDatabase pushDatabase = DatabaseFactory.getPushDatabase(getContext()); MessageDatabase smsDatabase = DatabaseFactory.getSmsDatabase(getContext());
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(getContext());
smsDatabase.removeMismatchedIdentity(messageRecord.getId(), smsDatabase.removeMismatchedIdentity(messageRecord.getId(),
mismatch.getRecipientId(getContext()), mismatch.getRecipientId(getContext()),
@@ -175,11 +150,11 @@ public class ConfirmIdentityDialog extends AlertDialog {
messageRecord.getDateSent(), messageRecord.getDateSent(),
legacy ? Base64.decode(messageRecord.getBody()) : null, legacy ? Base64.decode(messageRecord.getBody()) : null,
!legacy ? Base64.decode(messageRecord.getBody()) : null, !legacy ? Base64.decode(messageRecord.getBody()) : null,
0, null); 0,
0,
null);
long pushId = pushDatabase.insert(envelope); ApplicationDependencies.getJobManager().add(new PushDecryptMessageJob(getContext(), envelope, messageRecord.getId()));
ApplicationDependencies.getJobManager().add(new PushDecryptMessageJob(getContext(), pushId, messageRecord.getId()));
} catch (IOException e) { } catch (IOException e) {
throw new AssertionError(e); throw new AssertionError(e);
} }
@@ -19,20 +19,19 @@ package org.thoughtcrime.securesms;
import android.content.Context; import android.content.Context;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.thoughtcrime.securesms.logging.Log; import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.components.ContactFilterToolbar; import org.thoughtcrime.securesms.components.ContactFilterToolbar;
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode; import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper; import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme; import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import java.io.IOException; import java.io.IOException;
@@ -44,14 +43,16 @@ import java.lang.ref.WeakReference;
* @author Moxie Marlinspike * @author Moxie Marlinspike
* *
*/ */
public abstract class ContactSelectionActivity extends PassphraseRequiredActionBarActivity public abstract class ContactSelectionActivity extends PassphraseRequiredActivity
implements SwipeRefreshLayout.OnRefreshListener, implements SwipeRefreshLayout.OnRefreshListener,
ContactSelectionListFragment.OnContactSelectedListener ContactSelectionListFragment.OnContactSelectedListener,
ContactSelectionListFragment.ScrollCallback
{ {
private static final String TAG = ContactSelectionActivity.class.getSimpleName(); private static final String TAG = Log.tag(ContactSelectionActivity.class);
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme(); public static final String EXTRA_LAYOUT_RES_ID = "layout_res_id";
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
protected ContactSelectionListFragment contactsFragment; protected ContactSelectionListFragment contactsFragment;
@@ -60,18 +61,17 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActionB
@Override @Override
protected void onPreCreate() { protected void onPreCreate() {
dynamicTheme.onCreate(this); dynamicTheme.onCreate(this);
dynamicLanguage.onCreate(this);
} }
@Override @Override
protected void onCreate(Bundle icicle, boolean ready) { protected void onCreate(Bundle icicle, boolean ready) {
if (!getIntent().hasExtra(ContactSelectionListFragment.DISPLAY_MODE)) { if (!getIntent().hasExtra(ContactSelectionListFragment.DISPLAY_MODE)) {
int displayMode = TextSecurePreferences.isSmsEnabled(this) ? DisplayMode.FLAG_ALL int displayMode = Util.isDefaultSmsProvider(this) ? DisplayMode.FLAG_ALL
: DisplayMode.FLAG_PUSH | DisplayMode.FLAG_ACTIVE_GROUPS | DisplayMode.FLAG_INACTIVE_GROUPS; : DisplayMode.FLAG_PUSH | DisplayMode.FLAG_ACTIVE_GROUPS | DisplayMode.FLAG_INACTIVE_GROUPS | DisplayMode.FLAG_SELF;
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, displayMode); getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, displayMode);
} }
setContentView(R.layout.contact_selection_activity); setContentView(getIntent().getIntExtra(EXTRA_LAYOUT_RES_ID, R.layout.contact_selection_activity));
initializeToolbar(); initializeToolbar();
initializeResources(); initializeResources();
@@ -82,7 +82,6 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActionB
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
dynamicTheme.onResume(this); dynamicTheme.onResume(this);
dynamicLanguage.onResume(this);
} }
protected ContactFilterToolbar getToolbar() { protected ContactFilterToolbar getToolbar() {
@@ -90,10 +89,9 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActionB
} }
private void initializeToolbar() { private void initializeToolbar() {
this.toolbar = ViewUtil.findById(this, R.id.toolbar); this.toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(false); getSupportActionBar().setDisplayHomeAsUpEnabled(false);
getSupportActionBar().setDisplayShowTitleEnabled(false); getSupportActionBar().setDisplayShowTitleEnabled(false);
getSupportActionBar().setIcon(null); getSupportActionBar().setIcon(null);
@@ -102,7 +100,6 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActionB
private void initializeResources() { private void initializeResources() {
contactsFragment = (ContactSelectionListFragment) getSupportFragmentManager().findFragmentById(R.id.contact_selection_list_fragment); contactsFragment = (ContactSelectionListFragment) getSupportFragmentManager().findFragmentById(R.id.contact_selection_list_fragment);
contactsFragment.setOnContactSelectedListener(this);
contactsFragment.setOnRefreshListener(this); contactsFragment.setOnRefreshListener(this);
} }
@@ -116,11 +113,24 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActionB
} }
@Override @Override
public void onContactSelected(Optional<RecipientId> recipientId, String number) {} public boolean onBeforeContactSelected(Optional<RecipientId> recipientId, String number) {
return true;
}
@Override @Override
public void onContactDeselected(Optional<RecipientId> recipientId, String number) {} public void onContactDeselected(Optional<RecipientId> recipientId, String number) {}
@Override
public void onBeginScroll() {
hideKeyboard();
}
private void hideKeyboard() {
ServiceUtil.getInputMethodManager(this)
.hideSoftInputFromWindow(toolbar.getWindowToken(), 0);
toolbar.clearFocus();
}
private static class RefreshDirectoryTask extends AsyncTask<Context, Void, Void> { private static class RefreshDirectoryTask extends AsyncTask<Context, Void, Void> {
private final WeakReference<ContactSelectionActivity> activity; private final WeakReference<ContactSelectionActivity> activity;
@@ -18,41 +18,60 @@ package org.thoughtcrime.securesms;
import android.Manifest; import android.Manifest;
import android.animation.LayoutTransition;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.Button; import android.widget.Button;
import android.widget.HorizontalScrollView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment; import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
import androidx.fragment.app.FragmentActivity;
import androidx.loader.app.LoaderManager; import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader; import androidx.loader.content.Loader;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import androidx.transition.AutoTransition;
import androidx.transition.TransitionManager;
import com.annimon.stream.Collectors;
import com.annimon.stream.Stream;
import com.google.android.material.chip.ChipGroup;
import com.pnikosis.materialishprogress.ProgressWheel; import com.pnikosis.materialishprogress.ProgressWheel;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.components.RecyclerViewFastScroller; import org.thoughtcrime.securesms.components.RecyclerViewFastScroller;
import org.thoughtcrime.securesms.components.emoji.WarningTextView;
import org.thoughtcrime.securesms.contacts.AbstractContactsCursorLoader;
import org.thoughtcrime.securesms.contacts.ContactChip;
import org.thoughtcrime.securesms.contacts.ContactSelectionListAdapter; import org.thoughtcrime.securesms.contacts.ContactSelectionListAdapter;
import org.thoughtcrime.securesms.contacts.ContactSelectionListItem; import org.thoughtcrime.securesms.contacts.ContactSelectionListItem;
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader; import org.thoughtcrime.securesms.contacts.ContactsCursorLoader;
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode; import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
import org.thoughtcrime.securesms.contacts.SelectedContact; import org.thoughtcrime.securesms.contacts.SelectedContact;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper; import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
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.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.StickyHeaderDecoration; import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
@@ -66,7 +85,7 @@ import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import java.io.IOException; import java.io.IOException;
import java.util.LinkedList; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -76,39 +95,92 @@ import java.util.Set;
* @author Moxie Marlinspike * @author Moxie Marlinspike
* *
*/ */
public final class ContactSelectionListFragment extends Fragment public final class ContactSelectionListFragment extends LoggingFragment
implements LoaderManager.LoaderCallbacks<Cursor> implements LoaderManager.LoaderCallbacks<Cursor>
{ {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static final String TAG = Log.tag(ContactSelectionListFragment.class); private static final String TAG = Log.tag(ContactSelectionListFragment.class);
public static final String DISPLAY_MODE = "display_mode"; private static final int CHIP_GROUP_EMPTY_CHILD_COUNT = 1;
public static final String MULTI_SELECT = "multi_select"; private static final int CHIP_GROUP_REVEAL_DURATION_MS = 150;
public static final String REFRESHABLE = "refreshable";
public static final String RECENTS = "recents";
private TextView emptyText; public static final int NO_LIMIT = Integer.MAX_VALUE;
private Set<SelectedContact> selectedContacts;
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;
public static final String DISPLAY_MODE = "display_mode";
public static final String REFRESHABLE = "refreshable";
public static final String RECENTS = "recents";
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 WarningTextView groupLimit;
private OnSelectionLimitReachedListener onSelectionLimitReachedListener;
private AbstractContactsCursorLoaderFactoryProvider cursorFactoryProvider;
@Nullable private FixedViewsAdapter headerAdapter;
@Nullable private FixedViewsAdapter footerAdapter; @Nullable private FixedViewsAdapter footerAdapter;
@Nullable private InviteCallback inviteCallback; @Nullable private ListCallback listCallback;
@Nullable private ScrollCallback scrollCallback;
private GlideRequests glideRequests;
private SelectionLimits selectionLimit = SelectionLimits.NO_LIMITS;
private Set<RecipientId> currentSelection;
private boolean isMulti;
private boolean hideCount;
private boolean canSelectSelf;
@Override @Override
public void onAttach(@NonNull Context context) { public void onAttach(@NonNull Context context) {
super.onAttach(context); super.onAttach(context);
if (context instanceof InviteCallback) { if (context instanceof ListCallback) {
inviteCallback = (InviteCallback) context; 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;
} }
} }
@@ -130,14 +202,16 @@ public final class ContactSelectionListFragment extends Fragment
if (!TextSecurePreferences.hasSuccessfullyRetrievedDirectory(getActivity())) { if (!TextSecurePreferences.hasSuccessfullyRetrievedDirectory(getActivity())) {
handleContactPermissionGranted(); handleContactPermissionGranted();
} else { } else {
this.getLoaderManager().initLoader(0, null, this); LoaderManager.getInstance(this).initLoader(0, null, this);
} }
}) })
.onAnyDenied(() -> { .onAnyDenied(() -> {
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); FragmentActivity activity = requireActivity();
if (getActivity().getIntent().getBooleanExtra(RECENTS, false)) { activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
getLoaderManager().initLoader(0, null, ContactSelectionListFragment.this);
if (safeArguments().getBoolean(RECENTS, activity.getIntent().getBooleanExtra(RECENTS, false))) {
LoaderManager.getInstance(this).initLoader(0, null, ContactSelectionListFragment.this);
} else { } else {
initializeNoContactsPermission(); initializeNoContactsPermission();
} }
@@ -149,64 +223,157 @@ public final class ContactSelectionListFragment extends Fragment
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.contact_selection_list_fragment, container, false); View view = inflater.inflate(R.layout.contact_selection_list_fragment, container, false);
emptyText = ViewUtil.findById(view, android.R.id.empty); emptyText = view.findViewById(android.R.id.empty);
recyclerView = ViewUtil.findById(view, R.id.recycler_view); recyclerView = view.findViewById(R.id.recycler_view);
swipeRefresh = ViewUtil.findById(view, R.id.swipe_refresh); swipeRefresh = view.findViewById(R.id.swipe_refresh);
fastScroller = ViewUtil.findById(view, R.id.fast_scroller); fastScroller = view.findViewById(R.id.fast_scroller);
showContactsLayout = view.findViewById(R.id.show_contacts_container); showContactsLayout = view.findViewById(R.id.show_contacts_container);
showContactsButton = view.findViewById(R.id.show_contacts_button); showContactsButton = view.findViewById(R.id.show_contacts_button);
showContactsDescription = view.findViewById(R.id.show_contacts_description); showContactsDescription = view.findViewById(R.id.show_contacts_description);
showContactsProgress = view.findViewById(R.id.progress); showContactsProgress = view.findViewById(R.id.progress);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); 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);
swipeRefresh.setEnabled(getActivity().getIntent().getBooleanExtra(REFRESHABLE, true)); recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setItemAnimator(new DefaultItemAnimator() {
@Override
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder) {
return 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;
}
currentSelection = getCurrentSelection();
updateGroupLimit(getChipCount());
return view; return view;
} }
private @NonNull Bundle safeArguments() {
return getArguments() != null ? getArguments() : new Bundle();
}
private void updateGroupLimit(int chipCount) {
int members = currentSelection.size() + chipCount;
groupLimit.setText(getResources().getQuantityString(R.plurals.ContactSelectionListFragment_d_members, members, members));
groupLimit.setVisibility(isMulti && !hideCount ? View.VISIBLE : View.GONE);
groupLimit.setWarning(selectionWarningLimitExceeded());
}
@Override @Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults); Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
} }
public @NonNull List<SelectedContact> getSelectedContacts() { public @NonNull List<SelectedContact> getSelectedContacts() {
List<SelectedContact> selected = new LinkedList<>(); if (cursorRecyclerViewAdapter == null) {
if (selectedContacts != null) { return Collections.emptyList();
selected.addAll(selectedContacts);
} }
return selected; return cursorRecyclerViewAdapter.getSelectedContacts();
} }
private boolean isMulti() { public int getSelectedContactsCount() {
return getActivity().getIntent().getBooleanExtra(MULTI_SELECT, false); if (cursorRecyclerViewAdapter == null) {
return 0;
}
return cursorRecyclerViewAdapter.getSelectedContactsCount();
}
private Set<RecipientId> getCurrentSelection() {
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 isMulti;
} }
private void initializeCursor() { private void initializeCursor() {
glideRequests = GlideApp.with(this);
cursorRecyclerViewAdapter = new ContactSelectionListAdapter(requireContext(), cursorRecyclerViewAdapter = new ContactSelectionListAdapter(requireContext(),
GlideApp.with(this), glideRequests,
null, null,
new ListClickListener(), new ListClickListener(),
isMulti()); isMulti,
selectedContacts = cursorRecyclerViewAdapter.getSelectedContacts(); currentSelection);
RecyclerViewConcatenateAdapterStickyHeader concatenateAdapter = new RecyclerViewConcatenateAdapterStickyHeader(); RecyclerViewConcatenateAdapterStickyHeader concatenateAdapter = new RecyclerViewConcatenateAdapterStickyHeader();
if (listCallback != null) {
headerAdapter = new FixedViewsAdapter(createNewGroupItem(listCallback));
headerAdapter.hide();
concatenateAdapter.addAdapter(headerAdapter);
}
concatenateAdapter.addAdapter(cursorRecyclerViewAdapter); concatenateAdapter.addAdapter(cursorRecyclerViewAdapter);
if (inviteCallback != null) {
footerAdapter = new FixedViewsAdapter(createInviteActionView(inviteCallback)); if (listCallback != null) {
footerAdapter = new FixedViewsAdapter(createInviteActionView(listCallback));
footerAdapter.hide(); footerAdapter.hide();
concatenateAdapter.addAdapter(footerAdapter); concatenateAdapter.addAdapter(footerAdapter);
} }
recyclerView.setAdapter(concatenateAdapter); recyclerView.setAdapter(concatenateAdapter);
recyclerView.addItemDecoration(new StickyHeaderDecoration(concatenateAdapter, true, true)); recyclerView.addItemDecoration(new StickyHeaderDecoration(concatenateAdapter, true, true, 0));
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
if (scrollCallback != null) {
scrollCallback.onBeginScroll();
}
}
}
});
} }
private View createInviteActionView(@NonNull InviteCallback inviteCallback) { private View createInviteActionView(@NonNull ListCallback listCallback) {
View view = LayoutInflater.from(requireContext()) View view = LayoutInflater.from(requireContext())
.inflate(R.layout.contact_selection_invite_action_item, (ViewGroup) requireView(), false); .inflate(R.layout.contact_selection_invite_action_item, (ViewGroup) requireView(), false);
view.setOnClickListener(v -> inviteCallback.onInvite()); view.setOnClickListener(v -> listCallback.onInvite());
return view;
}
private View createNewGroupItem(@NonNull ListCallback listCallback) {
View view = LayoutInflater.from(requireContext())
.inflate(R.layout.contact_selection_new_group_item, (ViewGroup) requireView(), false);
view.setOnClickListener(v -> listCallback.onNewGroup(false));
return view; return view;
} }
@@ -242,23 +409,33 @@ public final class ContactSelectionListFragment extends Fragment
swipeRefresh.setRefreshing(false); swipeRefresh.setRefreshing(false);
} }
public boolean hasQueryFilter() {
return !TextUtils.isEmpty(cursorFilter);
}
public void setRefreshing(boolean refreshing) { public void setRefreshing(boolean refreshing) {
swipeRefresh.setRefreshing(refreshing); swipeRefresh.setRefreshing(refreshing);
} }
public void reset() { public void reset() {
selectedContacts.clear(); cursorRecyclerViewAdapter.clearSelectedContacts();
if (!isDetached() && !isRemoving() && getActivity() != null && !getActivity().isFinishing()) { if (!isDetached() && !isRemoving() && getActivity() != null && !getActivity().isFinishing()) {
getLoaderManager().restartLoader(0, null, this); LoaderManager.getInstance(this).restartLoader(0, null, this);
} }
} }
@Override @Override
public @NonNull Loader<Cursor> onCreateLoader(int id, Bundle args) { public @NonNull Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new ContactsCursorLoader(getActivity(), FragmentActivity activity = requireActivity();
getActivity().getIntent().getIntExtra(DISPLAY_MODE, DisplayMode.FLAG_ALL), int displayMode = safeArguments().getInt(DISPLAY_MODE, activity.getIntent().getIntExtra(DISPLAY_MODE, DisplayMode.FLAG_ALL));
cursorFilter, getActivity().getIntent().getBooleanExtra(RECENTS, false)); boolean displayRecents = safeArguments().getBoolean(RECENTS, activity.getIntent().getBooleanExtra(RECENTS, false));
if (cursorFactoryProvider != null) {
return cursorFactoryProvider.get().create();
} else {
return new ContactsCursorLoader.Factory(activity, displayMode, cursorFilter, displayRecents).create();
}
} }
@Override @Override
@@ -272,6 +449,14 @@ public final class ContactSelectionListFragment extends Fragment
footerAdapter.show(); footerAdapter.show();
} }
if (headerAdapter != null) {
if (TextUtils.isEmpty(cursorFilter)) {
headerAdapter.show();
} else {
headerAdapter.hide();
}
}
emptyText.setText(R.string.contact_selection_group_activity__no_contacts); emptyText.setText(R.string.contact_selection_group_activity__no_contacts);
boolean useFastScroller = data != null && data.getCount() > 20; boolean useFastScroller = data != null && data.getCount() > 20;
recyclerView.setVerticalScrollBarEnabled(!useFastScroller); recyclerView.setVerticalScrollBarEnabled(!useFastScroller);
@@ -323,8 +508,11 @@ public final class ContactSelectionListFragment extends Fragment
swipeRefresh.setVisibility(View.VISIBLE); swipeRefresh.setVisibility(View.VISIBLE);
reset(); reset();
} else { } else {
Toast.makeText(getContext(), R.string.ContactSelectionListFragment_error_retrieving_contacts_check_your_network_connection, Toast.LENGTH_LONG).show(); Context context = getContext();
initializeNoContactsPermission(); if (context != null) {
Toast.makeText(getContext(), R.string.ContactSelectionListFragment_error_retrieving_contacts_check_your_network_connection, Toast.LENGTH_LONG).show();
initializeNoContactsPermission();
}
} }
} }
}.execute(); }.execute();
@@ -336,7 +524,21 @@ public final class ContactSelectionListFragment extends Fragment
SelectedContact selectedContact = contact.isUsernameType() ? SelectedContact.forUsername(contact.getRecipientId().orNull(), contact.getNumber()) SelectedContact selectedContact = contact.isUsernameType() ? SelectedContact.forUsername(contact.getRecipientId().orNull(), contact.getNumber())
: SelectedContact.forPhone(contact.getRecipientId().orNull(), contact.getNumber()); : SelectedContact.forPhone(contact.getRecipientId().orNull(), contact.getNumber());
if (!isMulti() || !selectedContacts.contains(selectedContact)) { if (!canSelectSelf && Recipient.self().getId().equals(selectedContact.getOrCreateRecipientId(requireContext()))) {
Toast.makeText(requireContext(), R.string.ContactSelectionListFragment_you_do_not_need_to_add_yourself_to_the_group, Toast.LENGTH_SHORT).show();
return;
}
if (!isMulti || !cursorRecyclerViewAdapter.isSelectedContact(selectedContact)) {
if (selectionHardLimitReached()) {
if (onSelectionLimitReachedListener != null) {
onSelectionLimitReachedListener.onHardLimitReached(selectionLimit.getHardLimit());
} else {
GroupLimitDialog.showHardLimitMessage(requireContext());
}
return;
}
if (contact.isUsernameType()) { if (contact.isUsernameType()) {
AlertDialog loadingDialog = SimpleProgressDialog.show(requireContext()); AlertDialog loadingDialog = SimpleProgressDialog.show(requireContext());
@@ -346,31 +548,39 @@ public final class ContactSelectionListFragment extends Fragment
loadingDialog.dismiss(); loadingDialog.dismiss();
if (uuid.isPresent()) { if (uuid.isPresent()) {
Recipient recipient = Recipient.externalUsername(requireContext(), uuid.get(), contact.getNumber()); Recipient recipient = Recipient.externalUsername(requireContext(), uuid.get(), contact.getNumber());
selectedContacts.add(SelectedContact.forUsername(recipient.getId(), contact.getNumber())); SelectedContact selected = SelectedContact.forUsername(recipient.getId(), contact.getNumber());
contact.setChecked(true);
if (onContactSelectedListener != null) { if (onContactSelectedListener != null) {
onContactSelectedListener.onContactSelected(Optional.of(recipient.getId()), null); if (onContactSelectedListener.onBeforeContactSelected(Optional.of(recipient.getId()), null)) {
markContactSelected(selected);
cursorRecyclerViewAdapter.notifyItemRangeChanged(0, cursorRecyclerViewAdapter.getItemCount(), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
}
} else {
markContactSelected(selected);
cursorRecyclerViewAdapter.notifyItemRangeChanged(0, cursorRecyclerViewAdapter.getItemCount(), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
} }
} else { } else {
new AlertDialog.Builder(requireContext()) new AlertDialog.Builder(requireContext())
.setTitle(R.string.ContactSelectionListFragment_username_not_found) .setTitle(R.string.ContactSelectionListFragment_username_not_found)
.setMessage(getString(R.string.ContactSelectionListFragment_s_is_not_a_signal_user, contact.getNumber())) .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(); .show();
} }
}); });
} else { } else {
selectedContacts.add(selectedContact);
contact.setChecked(true);
if (onContactSelectedListener != null) { if (onContactSelectedListener != null) {
onContactSelectedListener.onContactSelected(contact.getRecipientId(), contact.getNumber()); if (onContactSelectedListener.onBeforeContactSelected(contact.getRecipientId(), contact.getNumber())) {
markContactSelected(selectedContact);
cursorRecyclerViewAdapter.notifyItemRangeChanged(0, cursorRecyclerViewAdapter.getItemCount(), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
}
} else {
markContactSelected(selectedContact);
cursorRecyclerViewAdapter.notifyItemRangeChanged(0, cursorRecyclerViewAdapter.getItemCount(), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
} }
} }
} else { } else {
selectedContacts.remove(selectedContact); markContactUnselected(selectedContact);
contact.setChecked(false); cursorRecyclerViewAdapter.notifyItemRangeChanged(0, cursorRecyclerViewAdapter.getItemCount(), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
if (onContactSelectedListener != null) { if (onContactSelectedListener != null) {
onContactSelectedListener.onContactDeselected(contact.getRecipientId(), contact.getNumber()); onContactSelectedListener.onContactDeselected(contact.getRecipientId(), contact.getNumber());
@@ -379,20 +589,160 @@ public final class ContactSelectionListFragment extends Fragment
} }
} }
public void setOnContactSelectedListener(OnContactSelectedListener onContactSelectedListener) { private boolean selectionHardLimitReached() {
this.onContactSelectedListener = onContactSelectedListener; 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) {
addChipForSelectedContact(selectedContact);
}
}
private void markContactUnselected(@NonNull SelectedContact selectedContact) {
cursorRecyclerViewAdapter.removeFromSelectedContacts(selectedContact);
cursorRecyclerViewAdapter.notifyItemRangeChanged(0, cursorRecyclerViewAdapter.getItemCount(), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
removeChipForContact(selectedContact);
}
private void removeChipForContact(@NonNull SelectedContact contact) {
for (int i = chipGroup.getChildCount() - 1; i >= 0; i--) {
View v = chipGroup.getChildAt(i);
if (v instanceof ContactChip && contact.matches(((ContactChip) v).getContact())) {
chipGroup.removeView(v);
}
}
updateGroupLimit(getChipCount());
if (getChipCount() == 0) {
setChipGroupVisibility(ConstraintSet.GONE);
}
}
private void addChipForSelectedContact(@NonNull SelectedContact selectedContact) {
SimpleTask.run(getViewLifecycleOwner().getLifecycle(),
() -> Recipient.resolved(selectedContact.getOrCreateRecipientId(requireContext())),
resolved -> addChipForRecipient(resolved, selectedContact));
}
private void addChipForRecipient(@NonNull Recipient recipient, @NonNull SelectedContact selectedContact) {
final ContactChip chip = new ContactChip(requireContext());
if (getChipCount() == 0) {
setChipGroupVisibility(ConstraintSet.VISIBLE);
}
chip.setText(recipient.getShortDisplayName(requireContext()));
chip.setContact(selectedContact);
chip.setCloseIconVisible(true);
chip.setOnCloseIconClickListener(view -> {
markContactUnselected(selectedContact);
if (onContactSelectedListener != null) {
onContactSelectedListener.onContactDeselected(Optional.of(recipient.getId()), recipient.getE164().orNull());
}
});
chipGroup.getLayoutTransition().addTransitionListener(new LayoutTransition.TransitionListener() {
@Override
public void startTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {
}
@Override
public void endTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {
if (view == chip && transitionType == LayoutTransition.APPEARING) {
chipGroup.getLayoutTransition().removeTransitionListener(this);
registerChipRecipientObserver(chip, recipient.live());
chipGroup.post(ContactSelectionListFragment.this::smoothScrollChipsToEnd);
}
}
});
chip.setAvatar(glideRequests, recipient, () -> addChip(chip));
}
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() {
int count = chipGroup.getChildCount() - CHIP_GROUP_EMPTY_CHILD_COUNT;
if (count < 0) throw new AssertionError();
return count;
}
private void registerChipRecipientObserver(@NonNull ContactChip chip, @Nullable LiveRecipient recipient) {
if (recipient != null) {
recipient.observe(getViewLifecycleOwner(), resolved -> {
if (chip.isAttachedToWindow()) {
chip.setAvatar(glideRequests, resolved, null);
chip.setText(resolved.getShortDisplayName(chip.getContext()));
}
});
}
}
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();
constraintSet.clone(constraintLayout);
constraintSet.setVisibility(R.id.chipGroupScrollContainer, visibility);
constraintSet.applyTo(constraintLayout);
} }
public void setOnRefreshListener(SwipeRefreshLayout.OnRefreshListener onRefreshListener) { public void setOnRefreshListener(SwipeRefreshLayout.OnRefreshListener onRefreshListener) {
this.swipeRefresh.setOnRefreshListener(onRefreshListener); this.swipeRefresh.setOnRefreshListener(onRefreshListener);
} }
private void smoothScrollChipsToEnd() {
int x = ViewUtil.isLtr(chipGroupScrollContainer) ? chipGroup.getWidth() : 0;
chipGroupScrollContainer.smoothScrollTo(x, 0);
}
public interface OnContactSelectedListener { public interface OnContactSelectedListener {
void onContactSelected(Optional<RecipientId> recipientId, String number); /** @return True if the contact is allowed to be selected, otherwise false. */
boolean onBeforeContactSelected(Optional<RecipientId> recipientId, String number);
void onContactDeselected(Optional<RecipientId> recipientId, String number); void onContactDeselected(Optional<RecipientId> recipientId, String number);
} }
public interface InviteCallback { public interface OnSelectionLimitReachedListener {
void onSuggestedLimitReached(int limit);
void onHardLimitReached(int limit);
}
public interface ListCallback {
void onInvite(); void onInvite();
void onNewGroup(boolean forceV1);
}
public interface ScrollCallback {
void onBeginScroll();
}
public interface AbstractContactsCursorLoaderFactoryProvider {
@NonNull AbstractContactsCursorLoader.Factory get();
} }
} }
@@ -1,101 +0,0 @@
package org.thoughtcrime.securesms;
import android.app.Activity;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.ListFragment;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import org.thoughtcrime.securesms.database.loaders.CountryListLoader;
import java.util.ArrayList;
import java.util.Map;
public class CountrySelectionFragment extends ListFragment implements LoaderManager.LoaderCallbacks<ArrayList<Map<String, String>>> {
private EditText countryFilter;
private CountrySelectedListener listener;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
return inflater.inflate(R.layout.country_selection_fragment, container, false);
}
@Override
public void onActivityCreated(Bundle bundle) {
super.onActivityCreated(bundle);
this.countryFilter = (EditText)getView().findViewById(R.id.country_search);
this.countryFilter.addTextChangedListener(new FilterWatcher());
getLoaderManager().initLoader(0, null, this).forceLoad();
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.listener = (CountrySelectedListener)activity;
}
@Override
public void onListItemClick(ListView listView, View view, int position, long id) {
Map<String, String> item = (Map<String, String>)this.getListAdapter().getItem(position);
if (this.listener != null) {
this.listener.countrySelected(item.get("country_name"),
Integer.parseInt(item.get("country_code").substring(1)));
}
}
@Override
public @NonNull Loader<ArrayList<Map<String, String>>> onCreateLoader(int arg0, Bundle arg1) {
return new CountryListLoader(getActivity());
}
@Override
public void onLoadFinished(@NonNull Loader<ArrayList<Map<String, String>>> loader,
ArrayList<Map<String, String>> results)
{
String[] from = {"country_name", "country_code"};
int[] to = {R.id.country_name, R.id.country_code};
this.setListAdapter(new SimpleAdapter(getActivity(), results, R.layout.country_list_item, from, to));
if (this.countryFilter != null && this.countryFilter.getText().length() != 0) {
((SimpleAdapter)getListAdapter()).getFilter().filter(this.countryFilter.getText().toString());
}
}
@Override
public void onLoaderReset(@NonNull Loader<ArrayList<Map<String, String>>> arg0) {
this.setListAdapter(null);
}
public interface CountrySelectedListener {
public void countrySelected(String countryName, int countryCode);
}
private class FilterWatcher implements TextWatcher {
@Override
public void afterTextChanged(Editable s) {
if (getListAdapter() != null) {
((SimpleAdapter)getListAdapter()).getFilter().filter(s.toString());
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
}
}
@@ -9,6 +9,7 @@ import android.content.ServiceConnection;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.os.Parcelable; import android.os.Parcelable;
import android.view.View; import android.view.View;
@@ -21,7 +22,7 @@ import org.thoughtcrime.securesms.database.SmsMigrator.ProgressDescription;
import org.thoughtcrime.securesms.service.ApplicationMigrationService; import org.thoughtcrime.securesms.service.ApplicationMigrationService;
import org.thoughtcrime.securesms.service.ApplicationMigrationService.ImportState; import org.thoughtcrime.securesms.service.ApplicationMigrationService.ImportState;
public class DatabaseMigrationActivity extends PassphraseRequiredActionBarActivity { public class DatabaseMigrationActivity extends PassphraseRequiredActivity {
private final ImportServiceConnection serviceConnection = new ImportServiceConnection(); private final ImportServiceConnection serviceConnection = new ImportServiceConnection();
private final ImportStateHandler importStateHandler = new ImportStateHandler(); private final ImportStateHandler importStateHandler = new ImportStateHandler();
@@ -150,7 +151,7 @@ public class DatabaseMigrationActivity extends PassphraseRequiredActionBarActivi
startActivity((Intent)getIntent().getParcelableExtra("next_intent")); startActivity((Intent)getIntent().getParcelableExtra("next_intent"));
} else { } else {
// TODO [greyson] Navigation // TODO [greyson] Navigation
startActivity(new Intent(this, MainActivity.class)); startActivity(MainActivity.clearTop(this));
} }
} }
@@ -158,6 +159,11 @@ public class DatabaseMigrationActivity extends PassphraseRequiredActionBarActivi
} }
private class ImportStateHandler extends Handler { private class ImportStateHandler extends Handler {
public ImportStateHandler() {
super(Looper.getMainLooper());
}
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
switch (message.what) { switch (message.what) {
@@ -16,20 +16,21 @@ import android.widget.Button;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat; 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.IdentityKeyUtil;
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil; import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.permissions.Permissions; import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.push.AccountManagerFactory;
import org.thoughtcrime.securesms.qr.ScanListener; import org.thoughtcrime.securesms.qr.ScanListener;
import org.thoughtcrime.securesms.util.Base64; import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask; import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
import org.whispersystems.libsignal.IdentityKeyPair; import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.InvalidKeyException; import org.whispersystems.libsignal.InvalidKeyException;
@@ -42,13 +43,13 @@ import org.whispersystems.signalservice.internal.push.DeviceLimitExceededExcepti
import java.io.IOException; import java.io.IOException;
public class DeviceActivity extends PassphraseRequiredActionBarActivity public class DeviceActivity extends PassphraseRequiredActivity
implements Button.OnClickListener, ScanListener, DeviceLinkFragment.LinkClickedListener 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 final DynamicLanguage dynamicLanguage = new DynamicLanguage();
private DeviceAddFragment deviceAddFragment; private DeviceAddFragment deviceAddFragment;
@@ -63,9 +64,14 @@ public class DeviceActivity extends PassphraseRequiredActionBarActivity
@Override @Override
public void onCreate(Bundle bundle, boolean ready) { public void onCreate(Bundle bundle, boolean ready) {
getSupportActionBar().setHomeAsUpIndicator(ContextCompat.getDrawable(this, R.drawable.ic_arrow_left_24)); setContentView(R.layout.device_activity);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(R.string.AndroidManifest__linked_devices); Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
requireSupportActionBar().setDisplayHomeAsUpEnabled(true);
requireSupportActionBar().setTitle(R.string.AndroidManifest__linked_devices);
this.deviceAddFragment = new DeviceAddFragment(); this.deviceAddFragment = new DeviceAddFragment();
this.deviceListFragment = new DeviceListFragment(); this.deviceListFragment = new DeviceListFragment();
this.deviceLinkFragment = new DeviceLinkFragment(); this.deviceLinkFragment = new DeviceLinkFragment();
@@ -74,20 +80,10 @@ public class DeviceActivity extends PassphraseRequiredActionBarActivity
this.deviceAddFragment.setScanListener(this); this.deviceAddFragment.setScanListener(this);
if (getIntent().getBooleanExtra("add", false)) { if (getIntent().getBooleanExtra("add", false)) {
initFragment(android.R.id.content, deviceAddFragment, dynamicLanguage.getCurrentLocale()); initFragment(R.id.fragment_container, deviceAddFragment, dynamicLanguage.getCurrentLocale());
} else { } 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 @Override
@@ -99,8 +95,9 @@ public class DeviceActivity extends PassphraseRequiredActionBarActivity
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { if (item.getItemId() == android.R.id.home) {
case android.R.id.home: finish(); return true; finish();
return true;
} }
return false; return false;
@@ -114,7 +111,7 @@ public class DeviceActivity extends PassphraseRequiredActionBarActivity
.withPermanentDenialDialog(getString(R.string.DeviceActivity_signal_needs_the_camera_permission_in_order_to_scan_a_qr_code)) .withPermanentDenialDialog(getString(R.string.DeviceActivity_signal_needs_the_camera_permission_in_order_to_scan_a_qr_code))
.onAllGranted(() -> { .onAllGranted(() -> {
getSupportFragmentManager().beginTransaction() getSupportFragmentManager().beginTransaction()
.replace(android.R.id.content, deviceAddFragment) .replace(R.id.fragment_container, deviceAddFragment)
.addToBackStack(null) .addToBackStack(null)
.commitAllowingStateLoss(); .commitAllowingStateLoss();
}) })
@@ -124,12 +121,12 @@ public class DeviceActivity extends PassphraseRequiredActionBarActivity
@Override @Override
public void onQrDataFound(final String data) { public void onQrDataFound(final String data) {
Util.runOnMain(() -> { ThreadUtil.runOnMain(() -> {
((Vibrator)getSystemService(Context.VIBRATOR_SERVICE)).vibrate(50); ((Vibrator)getSystemService(Context.VIBRATOR_SERVICE)).vibrate(50);
Uri uri = Uri.parse(data); Uri uri = Uri.parse(data);
deviceLinkFragment.setLinkClickedListener(uri, DeviceActivity.this); 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.setSharedElementReturnTransition(TransitionInflater.from(DeviceActivity.this).inflateTransition(R.transition.fragment_shared));
deviceAddFragment.setExitTransition(TransitionInflater.from(DeviceActivity.this).inflateTransition(android.R.transition.fade)); deviceAddFragment.setExitTransition(TransitionInflater.from(DeviceActivity.this).inflateTransition(android.R.transition.fade));
@@ -139,14 +136,14 @@ public class DeviceActivity extends PassphraseRequiredActionBarActivity
getSupportFragmentManager().beginTransaction() getSupportFragmentManager().beginTransaction()
.addToBackStack(null) .addToBackStack(null)
.addSharedElement(deviceAddFragment.getDevicesImage(), "devices") .addSharedElement(deviceAddFragment.getDevicesImage(), "devices")
.replace(android.R.id.content, deviceLinkFragment) .replace(R.id.fragment_container, deviceLinkFragment)
.commit(); .commit();
} else { } else {
getSupportFragmentManager().beginTransaction() getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.slide_from_bottom, R.anim.slide_to_bottom, .setCustomAnimations(R.anim.slide_from_bottom, R.anim.slide_to_bottom,
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) .addToBackStack(null)
.commit(); .commit();
} }
@@ -5,8 +5,6 @@ import android.annotation.TargetApi;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewAnimationUtils; import android.view.ViewAnimationUtils;
@@ -15,12 +13,14 @@ import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.components.camera.CameraView; import org.thoughtcrime.securesms.components.camera.CameraView;
import org.thoughtcrime.securesms.qr.ScanListener; import org.thoughtcrime.securesms.qr.ScanListener;
import org.thoughtcrime.securesms.qr.ScanningThread; import org.thoughtcrime.securesms.qr.ScanningThread;
import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.ViewUtil;
public class DeviceAddFragment extends Fragment { public class DeviceAddFragment extends LoggingFragment {
private ViewGroup container; private ViewGroup container;
private LinearLayout overlay; private LinearLayout overlay;
@@ -32,9 +32,9 @@ public class DeviceAddFragment extends Fragment {
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup viewGroup, Bundle bundle) { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup viewGroup, Bundle bundle) {
this.container = ViewUtil.inflate(inflater, viewGroup, R.layout.device_add_fragment); this.container = ViewUtil.inflate(inflater, viewGroup, R.layout.device_add_fragment);
this.overlay = ViewUtil.findById(this.container, R.id.overlay); this.overlay = this.container.findViewById(R.id.overlay);
this.scannerView = ViewUtil.findById(this.container, R.id.scanner); this.scannerView = this.container.findViewById(R.id.scanner);
this.devicesImage = ViewUtil.findById(this.container, R.id.devices); this.devicesImage = this.container.findViewById(R.id.devices);
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
this.overlay.setOrientation(LinearLayout.HORIZONTAL); this.overlay.setOrientation(LinearLayout.HORIZONTAL);
@@ -42,9 +42,9 @@ public class DeviceAddFragment extends Fragment {
this.overlay.setOrientation(LinearLayout.VERTICAL); 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() { this.container.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP) @TargetApi(21)
@Override @Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) int oldLeft, int oldTop, int oldRight, int oldBottom)
@@ -80,7 +80,7 @@ public class DeviceAddFragment extends Fragment {
} }
@Override @Override
public void onConfigurationChanged(Configuration newConfiguration) { public void onConfigurationChanged(@NonNull Configuration newConfiguration) {
super.onConfigurationChanged(newConfiguration); super.onConfigurationChanged(newConfiguration);
this.scannerView.onPause(); this.scannerView.onPause();
@@ -107,6 +107,4 @@ public class DeviceAddFragment extends Fragment {
this.scanningThread.setScanListener(scanListener); this.scanningThread.setScanListener(scanListener);
} }
} }
} }
@@ -3,13 +3,14 @@ package org.thoughtcrime.securesms;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
public class DeviceLinkFragment extends Fragment implements View.OnClickListener { public class DeviceLinkFragment extends Fragment implements View.OnClickListener {
private LinearLayout container; private LinearLayout container;
@@ -31,7 +32,7 @@ public class DeviceLinkFragment extends Fragment implements View.OnClickListener
} }
@Override @Override
public void onConfigurationChanged(Configuration newConfiguration) { public void onConfigurationChanged(@NonNull Configuration newConfiguration) {
super.onConfigurationChanged(newConfiguration); super.onConfigurationChanged(newConfiguration);
if (newConfiguration.orientation == Configuration.ORIENTATION_LANDSCAPE) { if (newConfiguration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
container.setOrientation(LinearLayout.HORIZONTAL); container.setOrientation(LinearLayout.HORIZONTAL);
@@ -6,15 +6,6 @@ import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; 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.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@@ -24,12 +15,21 @@ import android.widget.Button;
import android.widget.ListView; import android.widget.ListView;
import android.widget.Toast; 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 com.melnykov.fab.FloatingActionButton;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.database.loaders.DeviceListLoader; 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.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import java.io.IOException; import java.io.IOException;
@@ -41,7 +41,7 @@ public class DeviceListFragment extends ListFragment
ListView.OnItemClickListener, Button.OnClickListener 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 SignalServiceAccountManager accountManager;
private Locale locale; private Locale locale;
@@ -53,12 +53,12 @@ public class DeviceListFragment extends ListFragment
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
this.locale = (Locale) getArguments().getSerializable(PassphraseRequiredActionBarActivity.LOCALE_EXTRA); this.locale = (Locale) requireArguments().getSerializable(PassphraseRequiredActivity.LOCALE_EXTRA);
} }
@Override @Override
public void onAttach(Activity activity) { public void onAttach(@NonNull Context context) {
super.onAttach(activity); super.onAttach(context);
this.accountManager = ApplicationDependencies.getSignalServiceAccountManager(); this.accountManager = ApplicationDependencies.getSignalServiceAccountManager();
} }
@@ -68,7 +68,7 @@ public class DeviceListFragment extends ListFragment
this.empty = view.findViewById(R.id.empty); this.empty = view.findViewById(R.id.empty);
this.progressContainer = view.findViewById(R.id.progress_container); 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); this.addDeviceButton.setOnClickListener(this);
return view; return view;
@@ -122,67 +122,51 @@ public class DeviceListFragment extends ListFragment
final String deviceName = ((DeviceListItem)view).getDeviceName(); final String deviceName = ((DeviceListItem)view).getDeviceName();
final long deviceId = ((DeviceListItem)view).getDeviceId(); final long deviceId = ((DeviceListItem)view).getDeviceId();
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); AlertDialog.Builder builder = new MaterialAlertDialogBuilder(requireActivity());
builder.setTitle(getActivity().getString(R.string.DeviceListActivity_unlink_s, deviceName)); 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.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.setNegativeButton(android.R.string.cancel, null);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { builder.setPositiveButton(android.R.string.ok, (dialog, which) -> handleDisconnectDevice(deviceId));
@Override
public void onClick(DialogInterface dialog, int which) {
handleDisconnectDevice(deviceId);
}
});
builder.show(); builder.show();
} }
private void handleLoaderFailed() { 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.setMessage(R.string.DeviceListActivity_network_connection_failed);
builder.setPositiveButton(R.string.DeviceListActivity_try_again, builder.setPositiveButton(R.string.DeviceListActivity_try_again,
new DialogInterface.OnClickListener() { (dialog, which) -> getLoaderManager().restartLoader(0, null, DeviceListFragment.this));
@Override
public void onClick(DialogInterface dialog, int which) {
getLoaderManager().restartLoader(0, null, DeviceListFragment.this);
}
});
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { builder.setNegativeButton(android.R.string.cancel, (dialog, which) -> requireActivity().onBackPressed());
@Override builder.setOnCancelListener(dialog -> requireActivity().onBackPressed());
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.show(); builder.show();
} }
@SuppressLint("StaticFieldLeak") @SuppressLint("StaticFieldLeak")
private void handleDisconnectDevice(final long deviceId) { private void handleDisconnectDevice(final long deviceId) {
new ProgressDialogAsyncTask<Void, Void, Void>(getActivity(), new ProgressDialogAsyncTask<Void, Void, Boolean>(getActivity(),
R.string.DeviceListActivity_unlinking_device_no_ellipsis, R.string.DeviceListActivity_unlinking_device_no_ellipsis,
R.string.DeviceListActivity_unlinking_device) R.string.DeviceListActivity_unlinking_device)
{ {
@Override @Override
protected Void doInBackground(Void... params) { protected Boolean doInBackground(Void... params) {
try { try {
accountManager.removeDevice(deviceId); accountManager.removeDevice(deviceId);
return true;
} catch (IOException e) { } catch (IOException e) {
Log.w(TAG, e); Log.w(TAG, e);
Toast.makeText(getActivity(), R.string.DeviceListActivity_network_failed, Toast.LENGTH_LONG).show(); return false;
} }
return null;
} }
@Override @Override
protected void onPostExecute(Void result) { protected void onPostExecute(Boolean result) {
super.onPostExecute(result); super.onPostExecute(result);
getLoaderManager().restartLoader(0, null, DeviceListFragment.this); if (result) {
getLoaderManager().restartLoader(0, null, DeviceListFragment.this);
} else {
Toast.makeText(getActivity(), R.string.DeviceListActivity_network_failed, Toast.LENGTH_LONG).show();
}
} }
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
@@ -2,13 +2,16 @@ package org.thoughtcrime.securesms;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import androidx.appcompat.app.AlertDialog;
import android.view.Window; import android.view.Window;
public class DeviceProvisioningActivity extends PassphraseRequiredActionBarActivity { import androidx.appcompat.app.AlertDialog;
import org.signal.core.util.logging.Log;
public class DeviceProvisioningActivity extends PassphraseRequiredActivity {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static final String TAG = DeviceProvisioningActivity.class.getSimpleName(); private static final String TAG = Log.tag(DeviceProvisioningActivity.class);
@Override @Override
protected void onPreCreate() { protected void onPreCreate() {
@@ -17,9 +20,6 @@ public class DeviceProvisioningActivity extends PassphraseRequiredActionBarActiv
@Override @Override
protected void onCreate(Bundle bundle, boolean ready) { protected void onCreate(Bundle bundle, boolean ready) {
assert getSupportActionBar() != null;
getSupportActionBar().hide();
AlertDialog dialog = new AlertDialog.Builder(this) AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle(getString(R.string.DeviceProvisioningActivity_link_a_signal_device)) .setTitle(getString(R.string.DeviceProvisioningActivity_link_a_signal_device))
.setMessage(getString(R.string.DeviceProvisioningActivity_it_looks_like_youre_trying_to_link_a_signal_device_using_a_3rd_party_scanner)) .setMessage(getString(R.string.DeviceProvisioningActivity_it_looks_like_youre_trying_to_link_a_signal_device_using_a_3rd_party_scanner))
@@ -29,7 +29,7 @@ public class DeviceProvisioningActivity extends PassphraseRequiredActionBarActiv
startActivity(intent); startActivity(intent);
finish(); finish();
}) })
.setNegativeButton(R.string.DeviceProvisioningActivity_cancel, (dialog12, which) -> { .setNegativeButton(android.R.string.cancel, (dialog12, which) -> {
dialog12.dismiss(); dialog12.dismiss();
finish(); finish();
}) })
@@ -1,87 +0,0 @@
package org.thoughtcrime.securesms;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import org.thoughtcrime.securesms.util.ExpirationUtil;
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(context.getResources().getIntArray(R.array.expiration_times)[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 = context.getResources().getIntArray(R.array.expiration_times);
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;
}
public interface OnClickListener {
public void onClick(int expirationTime);
}
}

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