Compare commits

...

446 Commits

Author SHA1 Message Date
Greyson Parrelli 0a45b9b5e3 Bump version to 8.10.0 2026-05-06 13:21:37 -04:00
Greyson Parrelli 99b0061127 Update translations and other static files. 2026-05-06 13:21:07 -04:00
jeffrey-signal 7b11cc1676 Use GroupId navigation args for conversation settings instead of Parcelable. 2026-05-06 13:08:39 -04:00
jeffrey-signal 663e0a616e Fix message bubble caption exceeding the media width. 2026-05-06 13:08:39 -04:00
Alex Hart d05338cee0 Align sync message tracking with iOS. 2026-05-06 13:08:39 -04:00
Alex Hart ce294dbc0b Add mapping-based lazycolumn / lazyrow. 2026-05-06 13:08:39 -04:00
andrew-signal d0efd8d4b0 Bump to libsignal v0.93.2 2026-05-06 13:08:38 -04:00
Greyson Parrelli c8875b5ad1 Limit R8 threads to 1 to fix non-deterministic output. 2026-05-06 13:08:38 -04:00
jeffrey-signal 188458f772 Open chat tab conversation settings in the detail pane where available. 2026-05-06 13:08:38 -04:00
jeffrey-signal ed7fd10749 Split MainNavigationRouter into focused domain-specific routers. 2026-05-06 13:08:38 -04:00
Greyson Parrelli 2ffbf09b1b Fix lint crash by switching static-ips to properties. 2026-05-06 13:08:38 -04:00
Greyson Parrelli 799e57dbe9 Fix bug allowing concurrent execution of jobs in the same queue.
There was an issue where a higher priority job in the same queue would
become the new most eligible job, even if the current most eligible job
was actively running.
2026-05-06 13:08:38 -04:00
Greyson Parrelli 572c11ee6d Update to AGP 9.1.1 2026-05-06 13:08:38 -04:00
Alex Hart 4dd5a4ee53 Reduce Compose overhead on lower-end device.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-05-06 13:08:38 -04:00
Alex Hart 370fca3c89 Block screen recording during registration by applying FLAG_SECURE.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-05-06 13:08:38 -04:00
Cody Henthorne d91f130238 Update color and styling of release note update items. 2026-05-06 13:08:38 -04:00
Greyson Parrelli bb20432417 Fix verification message archive restore. 2026-05-06 13:08:38 -04:00
Greyson Parrelli 8138ea5f8f Show error dialog when ChallengeRequired has empty challenges list in change number flow. 2026-05-06 13:08:38 -04:00
Greyson Parrelli f235aa0599 Fix audio message timestamp truncation when playback speed toggle is visible. 2026-05-06 13:08:38 -04:00
jeffrey-signal c7d719e983 Fix message text sometimes overlapping the footer text.
Resolves signalapp/Signal-Android#13580
2026-05-06 13:08:38 -04:00
adel-signal cf71d43a2f Update DRED duration remote config away from global 2026-05-06 13:08:38 -04:00
Greyson Parrelli 1e70e825a3 Skip session switchover events from non-ACI contacts during backup export. 2026-05-06 13:08:38 -04:00
Greyson Parrelli cce1979716 Catch ForegroundServiceStartNotAllowedException in AttachmentProgressService listener. 2026-05-06 13:08:38 -04:00
Greyson Parrelli ad7e9c0fd7 Skip unlock animation to reduce screen lock dismiss latency. 2026-05-06 13:08:38 -04:00
Greyson Parrelli bd3e1e8059 Catch IllegalArgumentException when setting precomputed text with stale params. 2026-05-06 13:08:38 -04:00
Greyson Parrelli adb9e2173f Reroute ISE to NoSessionException. 2026-05-06 13:08:38 -04:00
Greyson Parrelli 958c6f451f Fix infinite spinner on RegistrationLockFragment when server rejects registration lock token. 2026-05-06 13:08:38 -04:00
Greyson Parrelli ab090236a1 Switch username scanner to use CameraScreen. 2026-05-06 13:08:38 -04:00
Greyson Parrelli 23698dbc28 Switch linked device scanner to use CameraScreen. 2026-05-06 13:08:38 -04:00
Greyson Parrelli 0542262c49 Improve error handling resiliance. 2026-05-06 13:08:38 -04:00
Greyson Parrelli e2d4ca9a4c Improve StorageSyncJob job data reliability. 2026-05-06 13:08:38 -04:00
Greyson Parrelli e54f3f501a Fix improper index usage on story queries. 2026-05-06 13:08:38 -04:00
Cody Henthorne 638d4997d1 Improve chat open performance when thread pool is saturated.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-05-06 13:08:38 -04:00
Jim Gustafson cbd05c4dff Update to RingRTC v2.68.1 2026-05-06 13:08:38 -04:00
andrew-signal ef396b5758 Bump libsignal to v0.93.1 2026-05-06 13:08:38 -04:00
Alex Hart 1d36ecafe1 Clean up back-pressed behavior which could result in an empty backstack and crash.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
Co-authored-by: jeffrey-signal <jeffrey@signal.org>
2026-05-06 13:08:38 -04:00
Alex Hart 07329c5b0d Migrate VerifyDisplayFragment to compose. 2026-05-06 13:08:38 -04:00
Alex Hart 7fc4ec3006 Migrate donation gateway sheet to compose. 2026-05-06 13:08:38 -04:00
Greyson Parrelli 9e7477bbeb Ensure that story error query uses proper index. 2026-05-06 13:08:38 -04:00
Alex Hart c83054906b Upgrade compose bom.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-05-06 13:08:38 -04:00
Cody Henthorne 011dc3495f Fix FiatMoneyTests run on non-US locales. 2026-05-06 13:08:38 -04:00
Greyson Parrelli 41b833e788 Improve deletion in all media screen. 2026-05-06 13:08:38 -04:00
Cody Henthorne e11f7225d3 Fix crash and subsequent retry after upload to archive fails length check. 2026-05-06 13:08:38 -04:00
Cody Henthorne bb261a3d85 Favor internal channel ids for recipients over externally created ones. 2026-05-06 13:08:38 -04:00
Greyson Parrelli 116f702be6 Add Live Queries tab to Spinner. 2026-05-06 13:08:38 -04:00
Cody Henthorne 4d09776277 Improve db usage around ensuring custom notification channel stae. 2026-05-06 13:08:38 -04:00
jeffrey-signal f32184c27e Fix padding around incoming caller name. 2026-05-06 13:08:38 -04:00
Greyson Parrelli 5fc037b324 Upgrade to SQLCipher 8.14.0 2026-05-06 13:08:38 -04:00
Cody Henthorne fc9d3e11e8 Only retrieve remote announcements during specific time window. 2026-05-06 13:08:38 -04:00
Cody Henthorne a951c7edfe Fix undownloaded voice note button UI bug. 2026-05-06 13:08:38 -04:00
Cody Henthorne 9d1714d452 Fix unique constraint crash when remapping recipients in name collision table. 2026-05-06 13:08:37 -04:00
Jordan Rose 9c2825f202 Consistently use core-util Hex utility class. 2026-05-06 13:08:37 -04:00
Greyson Parrelli a8969b34a4 Fix HUF currency formatting. 2026-05-06 13:08:37 -04:00
Cody Henthorne 1f59f3c2c4 Use correct wakelock for link device sync. 2026-05-06 13:08:37 -04:00
jeffrey-signal c6d91dce6e Convert ContextUtil to Kotlin. 2026-05-06 13:08:37 -04:00
jeffrey-signal 40c4633d41 Add utility method for resolving a FragmentActivity from Context. 2026-05-06 13:08:37 -04:00
Cody Henthorne edfe89683b Attempt to fix date headers overlaping scheduled messages. 2026-05-06 13:08:37 -04:00
Cody Henthorne cc3bedd154 Center release channel media bubbles in chat. 2026-05-06 13:08:37 -04:00
Cody Henthorne 56803a8850 Add internal preference to disable ANR induced crashing. 2026-05-06 13:08:37 -04:00
andrew-signal 2fdb712b38 Reattempt auth connection when network validated status changes. 2026-05-06 13:08:37 -04:00
Cody Henthorne 3d39045d1b Fix quickstart build failure. 2026-05-06 13:08:37 -04:00
Greyson Parrelli 90385b4e1c Fix flakey registration test. 2026-05-06 13:08:37 -04:00
Greyson Parrelli a02b66601c Remove support for END_SESSION message. 2026-05-06 13:08:37 -04:00
Alex Hart a83c57ff73 Use adaptive bitmap for dynamic shortcut icons to remove white border.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-05-06 13:08:37 -04:00
Alex Hart 3d063b38be Increase okhttp read/write timeouts for debug log uploads.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-05-06 13:08:37 -04:00
dependabot[bot] 03d20cb46a Update reproducible build dependencies. 2026-05-06 13:08:37 -04:00
Cody Henthorne 561186df90 Adjust auto-download checks. 2026-05-06 13:08:37 -04:00
Alex Hart fdcd21132c Update logic for processing qrs in CameraScreenViewModel. 2026-04-27 16:44:56 -04:00
Cody Henthorne 1043851423 Bump version to 8.9.1 2026-04-27 16:40:08 -04:00
Cody Henthorne 9bcbacc3d8 Update translations and other static files. 2026-04-27 16:40:08 -04:00
Cody Henthorne c2d7ee6926 Update release notes chat styling. 2026-04-27 16:39:59 -04:00
jeffrey-signal ceecacb47e Fix pull-to-refresh triggering when attempting to scroll up in contact search.
Resolves signalapp/Signal-Android#14742
2026-04-27 16:09:56 -04:00
Greyson Parrelli f4986273e4 Fix quote resolution failing for sent sync messages. 2026-04-27 13:34:52 -04:00
Greyson Parrelli 5f60adbe69 Update emoji_data.json 2026-04-27 13:34:52 -04:00
Alex Hart db6efeaf3d Revert "Migrate VerifyScanFragment to compose."
This reverts commit 9fa587b7e4.
2026-04-23 16:29:35 -03:00
Alex Hart 9b98b03971 Bump version to 8.9.0 2026-04-22 16:00:26 -03:00
Alex Hart dfbdf30535 Update baseline profile. 2026-04-22 15:49:27 -03:00
Alex Hart d567555047 Update translations and other static files. 2026-04-22 15:18:32 -03:00
Alex Hart 7658f6c36c Migrate ideal icon and copy. 2026-04-22 15:12:47 -03:00
Greyson Parrelli 51bd2d51c6 Add missing remember keys for pane anchors and preferred width to fix stale layout on resize. 2026-04-22 15:12:47 -03:00
Jesse Weinstein a00978d96e Two trivial parameter renaming fixes
Closes signalapp/Signal-Android#14736
2026-04-22 15:12:47 -03:00
jeffrey-signal b700529c3b Fix stuck outgoing messages when there a no remaining linked devices. 2026-04-22 15:12:47 -03:00
jeffrey-signal 4051cf739c Fix crash when long-pressing a message when in conversation bubble mode. 2026-04-22 15:12:47 -03:00
Alex Hart 6031fc9113 Modify heuristic for split-pane determination. 2026-04-22 15:12:47 -03:00
Michelle Tang 454fe86dda Adjust spinner in phone number screen. 2026-04-22 15:12:47 -03:00
Michelle Tang 92927ec69b Clear existing key transparency data. 2026-04-22 15:12:47 -03:00
Alex Hart 9fa587b7e4 Migrate VerifyScanFragment to compose. 2026-04-22 15:12:47 -03:00
Jesse Weinstein 552361dff4 Remove unused StickyListHeaders dependency.
Closes signalapp/Signal-Android#14729
2026-04-22 15:12:47 -03:00
Greyson Parrelli 78a25a6186 Restrict setExactAndAllowWhileIdle to API >= 31. 2026-04-22 15:12:47 -03:00
Cody Henthorne 58fcc07578 Convert flakey MessageTable story instrumentation tests to unit tests. 2026-04-22 15:12:47 -03:00
Cody Henthorne 8cd92a400c Add debug and testing apis to Spinner. 2026-04-22 15:12:47 -03:00
Greyson Parrelli 5d207932c9 Check instrumentation compilation in qa task. 2026-04-22 15:12:47 -03:00
Greyson Parrelli 7c147982c4 Supply size to attachment form endpoint for archive backfill. 2026-04-22 15:12:47 -03:00
Alex Hart bde1a94122 Parallelize file deletion when turning off local backups. 2026-04-22 15:12:47 -03:00
Alex Hart 2b66d7485a Fix PiP on-back behavior.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-04-22 15:12:47 -03:00
Greyson Parrelli 017b902c3c Increase regV5 test coverage. 2026-04-22 15:12:47 -03:00
dependabot[bot] 357fbfa8aa Update reproducible build dependencies. 2026-04-22 15:12:47 -03:00
Michelle Tang 0ce667f4af Update enter aep for large screens. 2026-04-22 15:12:47 -03:00
jeffrey-signal c4d78243c8 Fix message backups education screen typo. 2026-04-22 15:12:47 -03:00
Greyson Parrelli 51e12b2c76 Add flag to try different alarm for scheduled messages. 2026-04-22 15:12:47 -03:00
Greyson Parrelli 4dea1d8aa1 Move storage service operations into the network module. 2026-04-22 15:12:47 -03:00
Greyson Parrelli 89c645dea3 Create a network module. 2026-04-22 15:12:47 -03:00
Greyson Parrelli cd01d5f0b7 Enable remote mute for external users. 2026-04-17 17:00:09 -04:00
Michelle Tang 8730e28282 Update restore selection for large screens. 2026-04-17 16:31:59 -04:00
Greyson Parrelli 82046dd55f Add support for remote backup restore to regV5. 2026-04-17 15:54:24 -04:00
Cody Henthorne 76e30ab09f Add verified group title tracking and syncing. 2026-04-17 15:52:56 -04:00
Greyson Parrelli f680256f1d Remove range from copyright. 2026-04-17 15:26:52 -04:00
Michelle Tang da590a3241 Update verification code screen. 2026-04-17 15:26:52 -04:00
Alex Hart 91f73b473f Sanitize donations webview intents.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-04-17 15:26:52 -04:00
Alex Hart 53023517b3 Add authority check to VoiceCallShare. 2026-04-17 15:26:52 -04:00
Alex Hart 7f831e6806 Convert SafetyNumberReview dialogs to compose. 2026-04-17 15:26:51 -04:00
Alex Hart 77a18111e1 Convert search mediator to compose / viewmodel pattern. 2026-04-17 15:26:51 -04:00
Alex Hart 2a699a23dd Fix backup key verification megaphone ignoring snooze by using lastSeenTime.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-04-17 15:26:51 -04:00
Alex Hart 5643ffc1a9 Trust zero bottom inset when gesture navigation is detected on API <= 29. 2026-04-17 15:26:51 -04:00
Cody Henthorne 90207b7dd7 Convert handful of recipient/db heavy androidTests to regular unit tests. 2026-04-17 15:26:50 -04:00
andrew-signal 5b7f668251 Bump libsignal to v0.92.2 2026-04-17 15:26:50 -04:00
adel-signal 798bf3ec3e Update to RingRTC v2.68.0 2026-04-17 15:26:50 -04:00
Michelle Tang 1c77c9d3fb Check for valid phone number. 2026-04-17 15:26:50 -04:00
Michelle Tang dd52d78ee0 Update country picker for large screen. 2026-04-17 15:26:50 -04:00
Michelle Tang 4b1acca119 Scroll to initial country. 2026-04-17 15:26:49 -04:00
Michelle Tang 195fe60927 Update phone entry for large screen. 2026-04-17 15:26:49 -04:00
Cody Henthorne f427f31303 Improve group change defensive checks and update logic. 2026-04-17 15:26:49 -04:00
Greyson Parrelli fa19ed7ffc Use viewmodel entry scoping in regV5. 2026-04-17 15:26:49 -04:00
jeffrey-signal e5e99d4e03 Bump version to 8.8.2 2026-04-17 15:21:14 -04:00
jeffrey-signal 26d1a7ada7 Update baseline profile. 2026-04-17 15:00:00 -04:00
jeffrey-signal 5dd11e26e4 Update translations and other static files. 2026-04-17 14:53:54 -04:00
Alex Hart 9877b13c6e Add ability to launch into message backups checkout.
Co-authored-by: Cody Henthorne <cody@signal.org>
2026-04-17 12:33:52 -03:00
Greyson Parrelli d7d0fd3622 Rotate backup megaphone flag. 2026-04-17 10:09:12 -04:00
Sten Tijhuis 2439506c05 Update GitHub Actions versions and pin to commit SHAs.
Closes signalapp/Signal-Android#14715
2026-04-16 19:07:34 -04:00
jeffrey-signal 6088024f76 Revert "Use existing okhttp client + package checks for web apk."
This reverts commit df406633ff.
2026-04-16 19:01:09 -04:00
jeffrey-signal 9decd81cfc Bump version to 8.8.1 2026-04-16 14:25:08 -04:00
jeffrey-signal f27773a4e3 Update baseline profile. 2026-04-16 13:27:52 -04:00
jeffrey-signal 8d8c974a19 Update translations and other static files. 2026-04-16 13:20:10 -04:00
Cody Henthorne 1a3e81dcb0 Fix bad apostrophe escaping in new safety tip strings. 2026-04-16 13:08:59 -04:00
jeffrey-signal d5f85c0661 Bump version to 8.8.0 2026-04-15 20:18:12 -04:00
jeffrey-signal 91458f2702 Update baseline profile. 2026-04-15 20:18:12 -04:00
jeffrey-signal 6650ffc2c6 Update translations and other static files. 2026-04-15 20:17:59 -04:00
Cody Henthorne ab0102a372 Do not force-apply P2P group changes unless the change adds or removes us.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-04-15 14:45:14 -04:00
Cody Henthorne a797bbf850 Improve web socket behaviors around keep alive and shutdown. 2026-04-15 14:45:14 -04:00
Cody Henthorne 3804890265 Stop putting e164s into SignalProtocolAddress. 2026-04-15 14:45:14 -04:00
Greyson Parrelli fcdbf93626 Improve regV5 restore flows. 2026-04-15 14:45:14 -04:00
Michelle Tang f1b61f8f7e Add test dispatcher to phone number tests. 2026-04-15 14:45:14 -04:00
Michelle Tang ce582249ec Ask for permissions on the same screen. 2026-04-15 14:45:13 -04:00
Alex Hart b21a72153a Implement proper text-entry component for large screen media send flow. 2026-04-15 14:45:13 -04:00
jeffrey-signal 2a8bd20bb0 Fix sender name/label clipping in recycled conversation items.
Resolves signalapp/Signal-Android#14646
2026-04-15 14:45:13 -04:00
jeffrey-signal c30e3cc1b7 Disable group member labels while in message request state. 2026-04-15 14:45:13 -04:00
Greyson Parrelli 5fedd81921 Convert IndividualSendJob to kotlin. 2026-04-15 14:45:12 -04:00
jeffrey-signal 24069dc42e Fix self avatar in reaction bottom sheet. 2026-04-15 14:45:12 -04:00
Cody Henthorne ff15c8417a Clear upload spec when resume location is invalid in archive upload.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-04-15 14:45:12 -04:00
Greyson Parrelli cbf770d3ea Convert PushSendJob to kotlin. 2026-04-15 14:45:12 -04:00
Greyson Parrelli 676ab1ab6f Merge SendJob into PushSendJob. 2026-04-15 14:45:12 -04:00
Greyson Parrelli 9cc47942f2 Add process check to VoiceNotePlaybackService MediaSession access. 2026-04-15 14:45:12 -04:00
Greyson Parrelli 45e6e06c01 Improve error handling for empty prekey bundles. 2026-04-15 14:45:11 -04:00
Michelle Tang d2243707b5 Update permissions UI. 2026-04-15 14:45:11 -04:00
Jesse Weinstein 48cd1c1da0 Convert Windows line endings to Unix format.
Closes signalapp/Signal-Android#14632
2026-04-15 14:45:11 -04:00
thomasboom 330a5aece2 Show "None" for media auto-download when all options are disabled.
Co-authored-by: jeffrey-signal <jeffrey@signal.org>

Closes signalapp/Signal-Android#14678
2026-04-15 14:45:11 -04:00
Cody Henthorne 8c4f614d17 Allow reply action on notifications for messages with media attachments. 2026-04-15 14:45:11 -04:00
Leo Heitmann Ruiz f40bcb73fa Fix duplicate word in bug report template.
Closes signalapp/Signal-Android#14695
2026-04-15 14:45:10 -04:00
Jesse Weinstein 905a6f1a6b Fix typo in comment referencing ChatTypeSearchKey.
Closes signalapp/Signal-Android#14684
2026-04-15 14:45:10 -04:00
Jesse Weinstein 8f78471849 Remove the annimon.stream library.
Resolves #14719
2026-04-15 14:45:10 -04:00
Jesse Weinstein 82df20190d Remove all remaining usages of annimon.stream. 2026-04-15 14:45:10 -04:00
Greyson Parrelli 7f6e96a522 Check DownloadManager status to properly detect errors. 2026-04-15 14:45:09 -04:00
Greyson Parrelli eded335766 Fix potential crash when saving to fallback attachment folder.
Fixes #14720
2026-04-15 14:45:09 -04:00
Michelle Tang 7e4736969c Update country selection. 2026-04-15 14:45:09 -04:00
Greyson Parrelli 78940ffc17 Switch the labs plaintext export to share a single zip. 2026-04-15 14:45:09 -04:00
Jesse Weinstein 086883e565 Convert all the toList calls to collect(Collectors.toList)
Resolves #14718
2026-04-15 14:45:06 -04:00
Michelle Tang e9cdf0368e Update phone number UI. 2026-04-15 14:43:45 -04:00
Greyson Parrelli 7be273f461 Do not interrupt actively playing voice notes when locking. 2026-04-15 14:43:45 -04:00
Jesse Weinstein e6cbb0073c Remove more usages of annimon.stream.
Resolves #14717
2026-04-15 14:43:41 -04:00
Cody Henthorne 469421fcf3 Fix message request accepted to recipient from previous backup imports. 2026-04-15 14:43:12 -04:00
Greyson Parrelli 6d6d277277 Add share and forward entries to all media context menu. 2026-04-15 14:43:12 -04:00
jeffrey-signal 8a5faba985 Rename DragAndDrop -> DragToReorder to differentiate it from Android's drag-and-drop framework. 2026-04-15 14:43:12 -04:00
Cody Henthorne 7aadc208e1 Promptly remove terminated groups from shortcuts. 2026-04-15 14:43:11 -04:00
Greyson Parrelli 3c68e29679 Update image pasting to use ViewCompat.setOnReceiveContentListener. 2026-04-15 14:43:11 -04:00
Cody Henthorne 4756b8d70b Update conversation header and message request UI. 2026-04-15 14:43:11 -04:00
Alex Hart c2d927029a Add new ImageEditor compose component and wire in crop and drawing tools. 2026-04-13 16:25:00 -04:00
jeffrey-signal 629b96dd20 Fix wallpaper ANR regression while maintaining correct incoming message bubble colors. 2026-04-13 16:25:00 -04:00
Greyson Parrelli 01705459cf Include registered state in support email. 2026-04-13 16:25:00 -04:00
Greyson Parrelli c449f72786 Allow internal shares as long as they originate from our process. 2026-04-13 16:25:00 -04:00
Alex Hart 773d6c36dc Add large-screen media send toolbars for image editing. 2026-04-13 16:25:00 -04:00
andrew-signal b4bfb67a44 Bump to libsignal v0.91.2 2026-04-13 16:25:00 -04:00
Michelle Tang 3165c854df Remove unused strings. 2026-04-13 16:25:00 -04:00
Cody Henthorne f5cb1b0efa Restrict telecom usage to API 37. 2026-04-13 16:25:00 -04:00
Greyson Parrelli 179908fba6 Update registration error strings for SMS send failures. 2026-04-13 16:25:00 -04:00
Greyson Parrelli d6ec4bfbd3 Do not show getting started after local restore. 2026-04-13 16:25:00 -04:00
Greyson Parrelli 237ac9f94a Use original message timestamp for saved attachment MediaStore metadata.
Fixes #14584
2026-04-13 16:25:00 -04:00
Greyson Parrelli 66f69854cf Expand whitespace character detection in StringUtil.isVisuallyEmpty.
Fixes #14470
2026-04-13 16:25:00 -04:00
Greyson Parrelli 8f47592fc0 Fix reconciliation error for thumbnails for quotes. 2026-04-13 16:25:00 -04:00
Greyson Parrelli 3ea7bf77e0 Add release note validation check. 2026-04-13 16:25:00 -04:00
Greyson Parrelli 2b67b1c44f Remove legacy ClassicOpenHelper. 2026-04-13 16:25:00 -04:00
Jesse Weinstein ebccc6db30 Remove a lot of dead code.
Resolves #14672
2026-04-13 16:25:00 -04:00
Greyson Parrelli 98d9b12438 Add null check in UriUtil. 2026-04-13 16:22:10 -04:00
Greyson Parrelli 5db8463c70 Improve content proxy domain matching. 2026-04-13 16:22:10 -04:00
Greyson Parrelli 813252989b Notify CallRequestController after cancel. 2026-04-13 16:22:09 -04:00
Greyson Parrelli 0319adbce4 Add null check to orientation unboxing. 2026-04-13 16:22:09 -04:00
Greyson Parrelli de584ccb7d Use message digest for faster comparison. 2026-04-13 16:22:09 -04:00
Greyson Parrelli bd89c7fc39 Add null check to pin message import. 2026-04-13 16:22:09 -04:00
Greyson Parrelli bef4bb40ca Do not swallow IOException during backup creation. 2026-04-13 16:22:08 -04:00
Jesse Weinstein b57d922cdf Remove use of annimon.stream in several places.
Resolves #14705
2026-04-13 16:22:08 -04:00
Greyson Parrelli 8c1cc03c6f Use non-deprecated libsignal network constructor. 2026-04-13 16:22:08 -04:00
jeffrey-signal f0109f3e6b Improve drag-to-reorder auto scroll behavior when dragging an item up the list. 2026-04-13 16:22:08 -04:00
Greyson Parrelli ed89f3a78e Don't connect to the websocket if we know we're unregistered. 2026-04-13 16:22:07 -04:00
Alex Hart faa6a1d3f0 Welcome screen polish. 2026-04-13 16:22:07 -04:00
Greyson Parrelli 969635d942 Add redirect validation for link previews. 2026-04-13 16:22:07 -04:00
Greyson Parrelli 7665ae1464 Verify payment address identity key against local identity store. 2026-04-13 16:22:07 -04:00
Greyson Parrelli 9c18e3698e Apply CDN restrictions to quote attachments. 2026-04-13 16:22:07 -04:00
Greyson Parrelli df406633ff Use existing okhttp client + package checks for web apk. 2026-04-13 16:22:06 -04:00
Greyson Parrelli d121f9402b Improve quote validation. 2026-04-13 16:22:06 -04:00
Greyson Parrelli 5310c19b99 Update isValidExternalUri. 2026-04-13 16:22:06 -04:00
Greyson Parrelli cd92feb2b7 Write profile avatars to temp file before renaming to final location. 2026-04-13 16:22:06 -04:00
Greyson Parrelli 3b603f08ed Add defensive size check to stream read. 2026-04-13 16:22:06 -04:00
Greyson Parrelli 281f062b29 Remove the DeprecatedPersistentBlobProvider. 2026-04-13 16:22:05 -04:00
jeffrey-signal b054a7eb76 Bump version to 8.7.3 2026-04-13 16:15:41 -04:00
jeffrey-signal 33b9c88ecd Update baseline profile. 2026-04-13 15:40:05 -04:00
jeffrey-signal 253d36ae13 Update translations and other static files. 2026-04-13 15:32:54 -04:00
Michelle Tang 8306f8ec5b Improve collapsed set selection. 2026-04-13 14:05:20 -04:00
Michelle Tang 69b6d7ef9a Fix missing gallery photos.
Resolves signalapp/Signal-Android#14709
2026-04-13 14:05:00 -04:00
Greyson Parrelli aeeba3d2df Fix NPE when there's no retryafter duration. 2026-04-12 14:20:32 -04:00
Greyson Parrelli dfd2f7baf9 Bump version to 8.7.2 2026-04-09 22:44:57 -04:00
Greyson Parrelli 5de17a971d Update translations and other static files. 2026-04-09 22:44:34 -04:00
Greyson Parrelli 001896d244 Fix image transition animation. 2026-04-09 22:02:46 -04:00
Michelle Tang 1844b128e1 Use server timestamp for admin delete. 2026-04-09 17:17:55 -04:00
Michelle Tang 08623cc0c4 Use proper sender for early messages. 2026-04-09 15:44:35 -04:00
Greyson Parrelli f93a948169 Fix PIN creation loop during registration. 2026-04-09 13:48:46 -04:00
Cody Henthorne 76476191be Show better error ux for group calls you cannot start. 2026-04-09 10:27:44 -04:00
Greyson Parrelli d00bb28ee4 Bump version to 8.7.1 2026-04-08 22:10:47 -04:00
Greyson Parrelli 453e5bede7 Fix bad bubble tints for chats with wallpapers. 2026-04-08 22:04:17 -04:00
Michelle Tang c7c108bd77 Fix missing gallery photos. 2026-04-08 19:40:13 -04:00
Greyson Parrelli fb81574d35 Bump version to 8.7.0 2026-04-08 16:39:21 -04:00
Greyson Parrelli e6d3de091c Update translations and other static files. 2026-04-08 16:39:21 -04:00
Greyson Parrelli 99b8a6020d Fix flaky registration tests. 2026-04-08 16:39:21 -04:00
Greyson Parrelli 88b21b6113 Improve validator testing. 2026-04-08 16:39:21 -04:00
Greyson Parrelli 256ee9b1aa Delete unused apns database. 2026-04-08 16:39:21 -04:00
Alex Hart e2feaaf74c Add initial working E2E flow for MediaSendV3. 2026-04-08 16:39:21 -04:00
jeffrey-signal 17def87c17 Fix compose preview rendering when using Emojifier. 2026-04-08 16:39:20 -04:00
Alex Hart d90e9919ae Adaptive welcome screen with compact, medium, and large layouts. 2026-04-08 16:39:20 -04:00
Jim Gustafson 38baf17938 Update to RingRTC v2.67.2 2026-04-08 16:39:20 -04:00
scueZ 3f7707985f Skip confusing delete dialog body text in Note to Self.
Resolves #14708
2026-04-08 16:39:20 -04:00
jeffrey-signal a61072b249 Member label performance optimizations. 2026-04-08 16:39:20 -04:00
jeffrey-signal 80ff64ddd3 Prevent unregistered accounts from showing in group call participants. 2026-04-08 16:39:20 -04:00
Cody Henthorne 95c0467bda Show unanswered outgoing calls as unanswered. 2026-04-08 16:39:20 -04:00
Greyson Parrelli ff88d259fd Use long for key id. 2026-04-08 16:39:20 -04:00
Alex Hart 6e747019d4 Fix NPE in toPendingOneTimeDonation when waitForAuth is null.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-04-08 16:29:15 -04:00
Greyson Parrelli 9e7a40a63d Extend proper base activity. 2026-04-08 16:29:14 -04:00
Greyson Parrelli 38eed43046 Add long-press context menu in all media screen. 2026-04-08 15:50:43 -04:00
Greyson Parrelli 4c76cb682e Give a media/no-media choice in labs plaintext export. 2026-04-08 15:50:43 -04:00
Michelle Tang c47adb7482 Update padding sizes of update items. 2026-04-08 15:50:43 -04:00
Alex Hart 3c2ccef9a8 Fix upgrade card text color not adapting to dark mode.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-04-08 15:50:43 -04:00
jeffrey-signal fb0c4757f2 Fix media count indicator button colors so they match the chat color. 2026-04-08 15:50:43 -04:00
jeffrey-signal b8b9a632b5 Always prefetch wallpaper before opening a conversation. 2026-04-08 15:50:43 -04:00
Greyson Parrelli 9b4a13a491 Potential fix to configuration cache issues with translations. 2026-04-08 15:50:43 -04:00
Cody Henthorne 1cdd49721d Add logging around rotate storage id failures during storage sync. 2026-04-08 15:50:43 -04:00
Cody Henthorne 8b895738c0 Update telecom to 1.1.0-alpha04 2026-04-07 10:05:42 -04:00
Cody Henthorne 6ab3cd3390 Don't show terminated groups after storage service restore. 2026-04-07 09:39:06 -04:00
Alex Hart 11c8a726ec Increment localPlaintextExport flag to lock version. 2026-04-06 16:47:01 -04:00
Alex Hart 264447a6d9 Add breakpoint helper and expand device previews.
Co-authored-by: jeffrey-signal <jeffrey@signal.org>
2026-04-06 16:47:01 -04:00
Michelle Tang a7bb2831f8 Fix possible misuse of mp4 sanitizer. 2026-04-06 16:47:01 -04:00
Greyson Parrelli e05586a1c9 Convert RegistrationNetworkResult to RequestResult. 2026-04-06 16:47:01 -04:00
Greyson Parrelli 0e8dedf4d0 App ability to regV5 in the main app, behind compile flag. 2026-04-06 16:47:01 -04:00
Michelle Tang 0e11a1fe3e Add logs for voice note proximity. 2026-04-06 16:47:01 -04:00
adel-signal f1ebd2dc81 Add CallingAssetsDownloadJob to app startup to init calling assets
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-04-06 16:47:01 -04:00
Michelle Tang 8ea90c8a43 Cancel checking for messages on foreground. 2026-04-06 16:46:05 -04:00
Michelle Tang 6456dcf657 Fix potential edit message race condition. 2026-04-06 16:46:05 -04:00
Greyson Parrelli bb151c91e9 Add basic infra for regV5 local restore. 2026-04-06 16:46:05 -04:00
Greyson Parrelli ce6f39ae68 Update to the new attachment upload form libsignal method. 2026-04-06 16:46:05 -04:00
Greyson Parrelli 58e8ea08c2 Bump to libsignal v0.91.0 2026-04-06 16:46:05 -04:00
Michelle Tang 4dd74d9ab4 Fix collapsed tests. 2026-04-06 16:46:05 -04:00
Greyson Parrelli 3ef3a516b3 Prevent repeated storage-full notifications during backup.
When remote backup storage is full, hundreds of CopyAttachmentToArchiveJob
instances each independently call markOutOfRemoteStorageSpaceError(), which
re-posts the notification every time. Even though the notification ID is the
same, each call re-alerts the user with sound and vibration.

Guard markOutOfRemoteStorageSpaceError() to only post the notification once
by checking the flag before proceeding, and move the flag-set before the
notification post to prevent races. Also add an early exit in
CopyAttachmentToArchiveJob to skip the network quota check when already
marked as out of storage space.
2026-04-06 16:46:05 -04:00
Greyson Parrelli 518a81c7fa Do not start a call while one is in progress. 2026-04-06 16:46:05 -04:00
Michelle Tang f81325e7ca Pause voice notes when joining calls. 2026-04-06 16:46:05 -04:00
Greyson Parrelli cc847cb229 Fix potential glide lifecycle issue with transition animation. 2026-04-06 16:46:05 -04:00
Greyson Parrelli 7320a0ef46 Guard against potential crash when reacting to a message. 2026-04-06 16:46:05 -04:00
Greyson Parrelli 7c45686440 Fix potential missing ACI crash in verify screen. 2026-04-06 16:46:05 -04:00
Greyson Parrelli 8b5b83e974 Remove unnecessary transaction in LocalMetricsDatabase.
There was a native crash associated with it, unclear the cause, but
maybe this will help.
2026-04-06 16:46:05 -04:00
Michelle Tang a4a3861398 Disable proximity sensor when using headsets for voice notes. 2026-04-06 16:46:05 -04:00
Greyson Parrelli 01bdaaea84 Improve ANR stack trace perf. 2026-04-06 16:46:05 -04:00
Greyson Parrelli 1f02fba696 Include captcha info in support email template. 2026-04-06 16:46:04 -04:00
Greyson Parrelli aeb9054a63 Bump version to 8.6.2 2026-04-06 16:39:51 -04:00
Greyson Parrelli bb33945a93 Update translations and other static files. 2026-04-06 16:35:11 -04:00
Greyson Parrelli 3d2ceef47f Don't let the date validator starve the chat search. 2026-04-06 16:15:56 -04:00
Michelle Tang 892e6bd853 Fix OOM in collapse backfill job. 2026-04-06 12:15:35 -04:00
Alex Hart 78e1a407a6 Bump version to 8.6.1 2026-04-02 12:47:48 -03:00
Alex Hart 48d766ecff Update baseline profile. 2026-04-02 12:43:59 -03:00
Alex Hart d6d3226fcd Update translations and other static files. 2026-04-02 12:36:00 -03:00
Alex Hart ed4944f806 Write plaintext export to directory instead of zip, add notification content intent. 2026-04-02 12:15:14 -03:00
Alex Hart eb2dfb3fb6 Fix getViewLifecycleOwner crash in bubble view.post callback.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-04-02 11:33:23 -03:00
Alex Hart 265f71dff3 Surface error when local backup restore directory becomes inaccessible. 2026-04-02 11:27:22 -03:00
Michelle Tang 01d1769e4c Fix pinned message crash. 2026-04-02 10:26:58 -04:00
Alex Hart 97d099c7f1 Increment plaintext export config key. 2026-04-02 11:22:36 -03:00
Greyson Parrelli 0a957bc97c Fix crash when pressing volume buttons during active video recording. 2026-04-02 09:01:21 -04:00
Michelle Tang 5df7552506 Improve collapsed events with wallpapers. 2026-04-01 16:01:43 -04:00
Michelle Tang 75334abe0f Fix padding for collapsed events wrapping. 2026-04-01 14:58:37 -04:00
Michelle Tang 8524d20de5 Rotate collapse config. 2026-04-01 14:49:58 -04:00
Michelle Tang 495e2e043e Add various updates to collapsed events. 2026-04-01 10:49:37 -04:00
jeffrey-signal dec9eb613e Fix stale action cache save error and increase operations per run limit. 2026-04-01 10:07:03 -04:00
jeffrey-signal d6e7030dd0 Fix inactive pull request detection. 2026-03-31 17:54:13 -04:00
jeffrey-signal 6e43e931b2 Fix label applied to inactive issues. 2026-03-31 17:37:24 -04:00
Alex Hart 430a55f89f Bump version to 8.6.0 2026-03-31 16:49:29 -03:00
Alex Hart d717aad03d Update baseline profile. 2026-03-31 16:44:59 -03:00
Alex Hart efd86ad2fc Update translations and other static files. 2026-03-31 16:26:33 -03:00
Alex Hart b284835545 Move local backup progress tracking to in-memory object. 2026-03-31 16:20:26 -03:00
Alex Hart 4dd30f4ec3 Fix deactivated node crash in call screen layout.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-03-31 16:20:26 -03:00
Alex Hart a48938f3d8 Replace Environment bool with a RemoteConfig value. 2026-03-31 16:20:26 -03:00
Alex Hart 01989ad6e7 Fix issue with 12byte IV on older android versions. 2026-03-31 16:20:26 -03:00
Greyson Parrelli f37f67c6c0 Show optimized media in the all media view. 2026-03-31 16:20:26 -03:00
Greyson Parrelli 36f7c60a99 Improve camera mixed mode handling and clean up dead code. 2026-03-31 16:20:26 -03:00
Alex Hart 3f067654d9 Add plaintext chat history export UI. 2026-03-31 16:20:26 -03:00
Michelle Tang 0ce3eab3cd Fix scroll state of collapsed events. 2026-03-31 16:20:26 -03:00
jeffrey-signal b0f7c36cc2 Add additional group terminate checks to message processing.
Co-authored-by: Cody Henthorne <cody@signal.org>
2026-03-31 16:20:26 -03:00
Alex Hart 966e208be5 Fix DB write connection starvation in InAppPaymentsBottomSheetDelegate. 2026-03-31 16:20:26 -03:00
Greyson Parrelli a80d353e04 Fix issue where contact permission prompt wasn't dismissed. 2026-03-31 16:20:26 -03:00
Greyson Parrelli 080fa88bfb Improve handling of validating unpopulated profile field. 2026-03-31 16:20:26 -03:00
Michelle Tang 172e3d129e Fix attachment service crash due to timeout. 2026-03-31 16:20:26 -03:00
Alex Hart 52d5947c0a Treat 409 as successful redemption for recurring donation.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-03-31 16:20:26 -03:00
Alex Hart 7334ebfce1 Fix NPE in canUserAccessUnifiedBackupDirectory when backup directory is null.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-03-31 16:20:26 -03:00
Alex Hart 2c98bbaf7e Fix back navigation stuck in conversation after activity recreation.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-03-31 16:20:26 -03:00
Greyson Parrelli 5a91dba56e Update website variant manifest. 2026-03-31 16:20:26 -03:00
Greyson Parrelli 535c5a1574 Fix compile error in benchmarks. 2026-03-31 16:20:26 -03:00
Alex Hart b61c54c0e2 Fix thread header margin not accounting for status bar insets.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-03-31 16:20:26 -03:00
Alex Hart 5ac5d45fc6 Skip blocked/missing-keys info overlay for the local participant.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-03-31 16:20:26 -03:00
jeffrey-signal 79ba929e70 Fix selected photo missing checkmark in media gallery. 2026-03-31 16:20:26 -03:00
Cody Henthorne 3e9146a6f5 Improve device transfer reliability. 2026-03-31 16:20:26 -03:00
Michelle Tang 0c4c280a50 Reduce how often KT is reset. 2026-03-31 16:20:26 -03:00
Cody Henthorne ebea499a5a Add horizontal padding to call participant header. 2026-03-31 16:20:26 -03:00
Cody Henthorne d6b39e9f0a Respect phone number sharing privacy in call participant sheet. 2026-03-31 16:20:25 -03:00
Michelle Tang 787eaee6a0 Bump to libsignal v0.90.0
Co-authored-by: Andrew <andrew@signal.org>
2026-03-31 16:20:25 -03:00
Michelle Tang 5ecb3d8832 Fix pluralization of strings. 2026-03-31 16:20:25 -03:00
Greyson Parrelli b2e8666c9f Avoid chaining in BackupMessagesJob. 2026-03-31 16:20:25 -03:00
Greyson Parrelli 8af41e4b2c Fix image sometimes not showing immediately after send. 2026-03-31 16:20:25 -03:00
jeffrey-signal 5eaf1000c8 Prevent hidden recipients from appearing in recent conversations. 2026-03-31 16:20:25 -03:00
Cody Henthorne 4ed6773983 Exclude long text attachments when duplicating for incoming edits.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-03-31 16:20:25 -03:00
Greyson Parrelli 0de0441f65 Assign remote key to locally-split long text attachments during backup import. 2026-03-31 16:20:25 -03:00
Alex Hart 9e1b4a9a8c Add horizontal padding to pre-join call status text.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-03-31 16:20:25 -03:00
Greyson Parrelli bf28b90e89 Fix volume key interference during camera video recording. 2026-03-31 16:20:25 -03:00
jeffrey-signal a0a962a94f Fix sender name clipping in text-only incoming messages.
Resolves signalapp/Signal-Android#14646
2026-03-31 16:20:25 -03:00
Cody Henthorne abe0b2ebca Fix Backups settings row not rendering as disabled when unregistered. 2026-03-31 16:20:25 -03:00
Greyson Parrelli 7b4fe7ff40 Fix IndexOutOfBoundsException in story viewer back press. 2026-03-31 16:20:25 -03:00
Alex Hart 1ba9793943 Guard bubble inset request against detached view.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-03-31 16:20:25 -03:00
Cody Henthorne 14d4228e86 Retry StorageSyncJob on all IOExceptions. 2026-03-31 16:20:25 -03:00
Greyson Parrelli 3d2c51c14b Filter out revisions with mismatched authors during backup export. 2026-03-31 16:20:25 -03:00
Cody Henthorne 72d75e9cd5 Fix stale display names in search results. 2026-03-31 16:20:25 -03:00
Cody Henthorne e125fa6bfb Fix deadlock when sending media to story and group chat simultaneously. 2026-03-31 16:20:25 -03:00
benny10ben 57574126bb Fix deadlock when sending photo from camera to new contact.
Fixes #14674
Closes #14679
2026-03-31 16:20:25 -03:00
Greyson Parrelli 833c81a99e Guard against detached fragment in media preview error handlers. 2026-03-31 16:20:25 -03:00
Alex Hart 5ca17dfe52 Revert "Allow split pane on medium width."
This reverts commit a3d677533e2550897c7b548cb5b0bca199ec4287.
2026-03-31 16:20:25 -03:00
Alex Hart 5e058bb655 Allow split pane on medium width. 2026-03-31 16:20:25 -03:00
Cody Henthorne ce87b50a07 Add create-and-upload to important attachment upload flows.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-03-31 16:20:25 -03:00
Michelle Tang 2ad14800d1 Only get collapsed timer state when necessary. 2026-03-31 16:20:25 -03:00
Greyson Parrelli f04a0533cb Update SignalService.proto to match shared one. 2026-03-31 16:20:25 -03:00
Greyson Parrelli 5ae51f844e Drop legacy field from provisioning and sync messages. 2026-03-31 16:20:25 -03:00
jeffrey-signal 4ce2c6ef73 Replace legacy probot stale app with a GitHub actions workflow. 2026-03-31 10:19:46 -04:00
Cody Henthorne 4442f26f53 Bump version to 8.5.1 2026-03-27 16:13:39 -04:00
Cody Henthorne 849fce5a89 Update baseline profile. 2026-03-27 16:01:14 -04:00
Cody Henthorne 482fce6a25 Update translations and other static files. 2026-03-27 16:01:13 -04:00
Cody Henthorne e7e69ab064 Update group terminate strings. 2026-03-27 15:38:22 -04:00
Greyson Parrelli 4b768419da Prevent media gallery tabs from compressing text in some locales. 2026-03-27 15:10:00 -04:00
Greyson Parrelli 2cca01d30f Temporarily disable individual collisions. 2026-03-27 14:38:27 -04:00
Greyson Parrelli e0c69dc485 Fix images not showing up in message details. 2026-03-27 14:31:50 -04:00
Greyson Parrelli 1dd79efdb2 Fix select-all in the all media view. 2026-03-27 14:13:49 -04:00
Cody Henthorne dbb3c8def9 Fall back to next challenge when push challenge fails during registration.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-03-27 13:40:50 -04:00
Cody Henthorne 562185f46d Insert terminate event when restoring ended group from storage service. 2026-03-27 13:38:14 -04:00
Alex Hart f6c7c6de73 Fix local archive progression reporting in notification. 2026-03-27 12:38:36 -03:00
Greyson Parrelli 1ca3a9ca73 Fix unpin sync messages for 1:1 conversations. 2026-03-27 11:23:46 -04:00
jeffrey-signal c76c3f65f2 Fix notification reply avatar showing note to self instead of profile photo. 2026-03-27 11:21:14 -04:00
jeffrey-signal 59c27797d6 Fix backup validation error when a group member has a label emoji value without a label string. 2026-03-27 10:15:58 -04:00
Greyson Parrelli c5c720b1c9 Enforce length limits on link preview fields. 2026-03-26 15:57:36 -04:00
Greyson Parrelli caa09c82d0 Fix some APNGs not playing in new renderer. 2026-03-26 15:47:03 -04:00
Greyson Parrelli d45f80f25d Improve APNG validation in new APNG renderer. 2026-03-26 15:39:03 -04:00
Greyson Parrelli 6a248f617a Include links in the "All" tab of media overview. 2026-03-26 15:24:56 -04:00
Greyson Parrelli 2959e05ea7 Fix link multi-selection in media overview. 2026-03-26 15:24:56 -04:00
Cody Henthorne 17faf56388 Drop all messages sent to a terminated group. 2026-03-26 15:22:20 -04:00
Alex Hart f533ad1533 Update copy for backup education screen. 2026-03-26 16:15:05 -03:00
Alex Hart 25452fefa5 Retry canWrite() check when opening backup directory for writing.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2026-03-26 14:54:10 -03:00
Cody Henthorne 9702728c19 Gate poll, pin, and reaction UX in terminated groups. 2026-03-26 13:26:16 -04:00
Cody Henthorne 43f19d14d8 Add additional checks for terminated groups during send flows. 2026-03-26 11:59:11 -04:00
Alex Hart 467c154ea6 Utilize enqueue job for spawning attachment restore jobs. 2026-03-26 12:41:41 -03:00
Alex Hart d72c742ab6 Remove hint file. 2026-03-26 12:35:34 -03:00
Alex Hart 567bf0facc Add Last Backup help text. 2026-03-26 12:30:59 -03:00
Alex Hart d5329d0794 Support directly selecting signalbackup. 2026-03-26 12:25:37 -03:00
Alex Hart ff04e5c5c3 Ensure metadata is available when writing chat style attachments. 2026-03-26 10:51:51 -03:00
Alex Hart e529fbd1bc Suppress megaphone for upgrade path. 2026-03-26 09:41:47 -03:00
Cody Henthorne 068eaff801 Bump version to 8.5.0 2026-03-25 17:02:37 -04:00
Cody Henthorne e0bb3a48c2 Update translations and other static files. 2026-03-25 16:41:04 -04:00
Alex Hart f2e4881026 Add underpinnings to allow for local plaintext export.
Co-authored-by: Cody Henthorne <cody@signal.org>
2026-03-25 16:31:10 -04:00
Alex Hart b605148ac4 Wake lock during restore. 2026-03-25 16:31:10 -04:00
Cody Henthorne 2b9126d74b Update group terminated banner. 2026-03-25 16:31:10 -04:00
Alex Hart 206f6d84e7 Remove size line from backup info. 2026-03-25 16:31:09 -04:00
Greyson Parrelli 01836b3a7c Update emoji to unicode 17. 2026-03-25 16:31:09 -04:00
Michelle Tang e68691c966 Show final disappearing timer value for collapsed events. 2026-03-25 16:31:09 -04:00
Alex Hart 957f473e77 Ensure we upgrade properly from v1. 2026-03-25 16:31:09 -04:00
Alex Hart 8a023100ea Write backup file timestamp in utc. 2026-03-25 16:31:09 -04:00
Alex Hart 5bfdca509c Fix dark mode on update card. 2026-03-25 16:31:09 -04:00
Tushar Soni 9a837254ec Simplify recipient list truncation in CreateFolderScreen.
Resolves signalapp/Signal-Android#14439
Closes signalapp/Signal-Android#14473
2026-03-25 16:31:09 -04:00
Alex Hart 3f27769d20 Enable new local backup export for external users. 2026-03-25 16:31:09 -04:00
Michelle Tang 4f260c2063 Backfill collapsible messages. 2026-03-25 16:31:09 -04:00
Michelle Tang 75df16e842 Fix collapsing tests. 2026-03-25 16:31:09 -04:00
Michelle Tang fce6651e26 Fix pinned messages with attachments. 2026-03-25 16:31:09 -04:00
andrew-signal b06783bc90 Bump to libsignal v0.89.2 2026-03-25 16:31:09 -04:00
Jesse Weinstein 72a1a9b0ff Fix unquoted imports in proto files.
Closes signalapp/Signal-Android#14669
2026-03-25 16:31:09 -04:00
DivyaKhunt07 5568a14490 Fix unexpected keyboard appearance on repeated back swipe.
Resolves signalapp/Signal-Android#14618
Closes signalapp/Signal-Android#14633
2026-03-25 16:31:09 -04:00
Michelle Tang 378ebb00c4 Allow multiselect deleting for collapsed events. 2026-03-25 16:31:09 -04:00
Cody Henthorne c81f40eb74 Add additional group terminate checks. 2026-03-25 16:31:09 -04:00
Alex Hart d97bde3959 Update to utilize main activity instead of passthrough. 2026-03-25 16:31:09 -04:00
jeffrey-signal 4d301a4f66 Show conversation settings in the detail pane on large screens. 2026-03-25 16:31:09 -04:00
Alex Hart 9941b2d123 Fix several bugs in the local backup restore flow. 2026-03-25 16:31:09 -04:00
Greyson Parrelli 089d8a50b2 Promote the new APNG renderer to a normal flag. 2026-03-25 16:31:09 -04:00
Greyson Parrelli eb8ad5218d Filter archived stories from the stories landing page query. 2026-03-25 16:31:09 -04:00
Michelle Tang 21b1401fc4 Update safety number tappable area. 2026-03-25 16:31:09 -04:00
Michelle Tang 58ea9a1f48 Rename collapsed events for 1:1. 2026-03-25 16:31:09 -04:00
Greyson Parrelli 2bb9578ef9 Use sqlite-jdbc for unit tests to enable FTS5 and JSON1 support. 2026-03-25 16:31:09 -04:00
Michelle Tang c3b8768570 Turn on collapsing chat events for internal users. 2026-03-25 16:31:09 -04:00
Alex Hart 94e3dabc20 Confirm backup location after successful local backup restore. 2026-03-25 16:31:09 -04:00
Jesse Weinstein 542a820e22 Remove UriSerializer typealias -- it is only used in two places 2026-03-25 16:31:09 -04:00
Greyson Parrelli 8f7cc52255 Fix bug around collision detection filtering. 2026-03-25 16:31:09 -04:00
Greyson Parrelli 63888f1c99 Refactor name collision tables to improve perf. 2026-03-25 16:31:09 -04:00
jeffrey-signal a588522c9b Support navigating back to MainActivity with no conversation selected. 2026-03-25 16:31:09 -04:00
Greyson Parrelli 7a2eca3bd5 Fix all media storage overview performance. 2026-03-25 16:31:09 -04:00
Greyson Parrelli a8ba0dccca Fix story reply thumbnails. 2026-03-25 16:31:09 -04:00
Greyson Parrelli 782c83cc4e Fix story download bug. 2026-03-25 16:31:09 -04:00
Greyson Parrelli 46e6ae915c Add better loading states for story archive and starred. 2026-03-25 16:31:09 -04:00
Greyson Parrelli 8a887b65a1 Extract base archive classes into their own module. 2026-03-25 16:31:09 -04:00
Greyson Parrelli 08491579dd Add links to the all media view. 2026-03-25 16:31:09 -04:00
Greyson Parrelli 25b01a30be Improve memory usage of new APNG renderer by making it streaming. 2026-03-25 16:31:09 -04:00
Greyson Parrelli 48374e6950 Add support for starring messages. 2026-03-25 16:31:09 -04:00
jeffrey-signal 6496f236ea Fix secure backups learn more link.
Resolves signalapp/Signal-Android#14657
2026-03-25 16:31:09 -04:00
Alex Hart e767434c2b Perform StorageServiceRestore on skip if already registered. 2026-03-25 16:31:09 -04:00
Michelle Tang bb6507a456 Disabled new lines for when statements for ktlint. 2026-03-25 16:31:09 -04:00
Greyson Parrelli c3f9e5d972 Add new APNG renderer, just for internal users for now. 2026-03-25 16:31:08 -04:00
Alex Hart 34d87cf6e1 Warning dialogs for local backup restore. 2026-03-25 16:31:08 -04:00
Greyson Parrelli e657a4adf3 Guard auto-lower hand behind labs. 2026-03-25 16:31:08 -04:00
jeffrey-signal 9594599d60 Fix unread filter deactivating when scrolling through the conversation list. 2026-03-25 16:31:08 -04:00
Cody Henthorne a0c0acb8fc Add group terminate support. 2026-03-25 16:31:08 -04:00
Greyson Parrelli 0896718e5c Annotate labs features as such. 2026-03-25 16:31:08 -04:00
Greyson Parrelli be4bf27ede Remove attachment table JSON join. 2026-03-25 16:31:08 -04:00
Greyson Parrelli 7253aaaa14 Add the ability to filter search by date and author. 2026-03-25 16:31:08 -04:00
jeffrey-signal 72cbe61f6c Prepare conversation fragment navigation for two-pane conversation settings. 2026-03-25 16:31:08 -04:00
Alex Hart 78d3db319c Fix local backup restore AEP handling and conditional re-enable. 2026-03-25 16:31:08 -04:00
Greyson Parrelli c7a6c7ad9e Minor improvements to SVRB error handling. 2026-03-25 16:31:08 -04:00
Greyson Parrelli 8bc183b994 Fix validation error with session switchover events. 2026-03-25 16:31:08 -04:00
Greyson Parrelli ef6e5abc17 Add retry logic for camera binding failures. 2026-03-25 16:31:08 -04:00
Greyson Parrelli e96e6e8d18 Use note to self icon in share sheet. 2026-03-25 16:31:08 -04:00
Greyson Parrelli cee33a23ac Use transaction when loading logs. 2026-03-25 16:31:08 -04:00
Greyson Parrelli c5de7581ee Show error message on SN screen when there's no ACI. 2026-03-25 16:31:08 -04:00
Greyson Parrelli 5dc626078f Compress shared contact avatar before launching add-to-contacts intent.
Old way let us use photos that could put us over the 1mb transaction
size limit.
2026-03-25 16:31:08 -04:00
Greyson Parrelli 9de75b3e1f Show groups that have the same member list during group creation. 2026-03-25 16:31:08 -04:00
Greyson Parrelli f09bf5b14c Make regV5 resumable if the app closes. 2026-03-19 17:13:11 -04:00
1738 changed files with 95509 additions and 37394 deletions
+1
View File
@@ -20,6 +20,7 @@ ktlint_standard_unnecessary-parentheses-before-trailing-lambda = disabled
ktlint_standard_value-parameter-comment = disabled
ktlint_standard_class-signature = disabled
ktlint_standard_function-expression-body = disabled
ktlint_standard_blank-line-between-when-conditions = disabled
# Disable ktlint on generated source code, see
# https://github.com/JLLeitschuh/ktlint-gradle/issues/746
+1 -1
View File
@@ -17,7 +17,7 @@ body:
label: "Guidelines"
description: "Search issues here: https://github.com/signalapp/Signal-Android/issues/?q=is%3Aissue+"
options:
- label: I have searched searched open and closed issues for duplicates
- label: I have searched open and closed issues for duplicates
required: true
- label: I am submitting a bug report for existing functionality that does not work as intended
required: true
+27
View File
@@ -0,0 +1,27 @@
version: 2
updates:
# Automatically keep GitHub Actions SHA-pinned to the latest commit SHAs.
# Dependabot will update both the SHA and the inline version comment (e.g. # v6)
# while leaving any extra documentation comments intact.
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
labels:
- "dependencies"
commit-message:
prefix: "ci"
groups:
actions:
patterns:
- "actions/*"
gradle-actions:
patterns:
- "gradle/*"
peter-evans:
patterns:
- "peter-evans/*"
usefulness:
patterns:
- "usefulness/*"
-23
View File
@@ -1,23 +0,0 @@
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 60
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 7
issues:
exemptLabels:
- acknowledged
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale Issue or Pull Request.
closeComment: >
This issue has been closed due to inactivity.
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 1
+8 -4
View File
@@ -16,26 +16,30 @@ jobs:
runs-on: ubuntu-latest-8-cores
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
# gh api repos/actions/checkout/commits/v6 --jq '.sha'
with:
submodules: true
- name: set up JDK 17
uses: actions/setup-java@v4
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
# gh api repos/actions/setup-java/commits/v5 --jq '.sha'
with:
distribution: temurin
java-version: 17
cache: gradle
- name: Validate Gradle Wrapper
uses: gradle/actions/wrapper-validation@v5
uses: gradle/actions/wrapper-validation@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6
# gh api repos/gradle/actions/commits/v6 --jq '.sha'
- name: Build with Gradle
run: ./gradlew qa
- name: Archive reports for failed build
if: ${{ failure() }}
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
# gh api repos/actions/upload-artifact/commits/v7 --jq '.sha'
with:
name: reports
path: '*/build/reports'
+19 -10
View File
@@ -14,15 +14,17 @@ jobs:
assemble-base:
if: ${{ github.repository != 'signalapp/Signal-Android' }}
runs-on: ubuntu-latest-8-cores
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
# gh api repos/actions/checkout/commits/v6 --jq '.sha'
with:
submodules: true
ref: ${{ github.event.pull_request.base.sha }}
- name: set up JDK 17
uses: actions/setup-java@v3
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
# gh api repos/actions/setup-java/commits/v5 --jq '.sha'
with:
distribution: temurin
java-version: 17
@@ -32,11 +34,13 @@ jobs:
run: echo "y" | ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager --install "ndk;${{ env.NDK_VERSION }}"
- name: Validate Gradle Wrapper
uses: gradle/actions/wrapper-validation@v5
uses: gradle/actions/wrapper-validation@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6
# gh api repos/gradle/actions/commits/v6 --jq '.sha'
- name: Cache base apk
id: cache-base
uses: actions/cache@v4
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
# gh api repos/actions/cache/commits/v5 --jq '.sha'
with:
path: diffuse-base.apk
key: diffuse-${{ github.event.pull_request.base.sha }}
@@ -49,7 +53,8 @@ jobs:
if: steps.cache-base.outputs.cache-hit != 'true'
run: mv app/build/outputs/apk/playProd/release/*arm64*.apk diffuse-base.apk
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
# gh api repos/actions/checkout/commits/v6 --jq '.sha'
with:
submodules: true
clean: 'false'
@@ -61,18 +66,21 @@ jobs:
run: mv app/build/outputs/apk/playProd/release/*arm64*.apk diffuse-new.apk
- id: diffuse
uses: usefulness/diffuse-action@v1
uses: usefulness/diffuse-action@41995fe8ff6be0a8847e63bdc5a4679c704b455c # v1
# gh api repos/usefulness/diffuse-action/commits/v1 --jq '.sha'
with:
old-file-path: diffuse-base.apk
new-file-path: diffuse-new.apk
- uses: peter-evans/find-comment@v2
- uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4
# gh api repos/peter-evans/find-comment/commits/v4 --jq '.sha'
id: find-comment
with:
issue-number: ${{ github.event.pull_request.number }}
body-includes: Diffuse output
- uses: peter-evans/create-or-update-comment@v3
- uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5
# gh api repos/peter-evans/create-or-update-comment/commits/v5 --jq '.sha'
with:
body: |
Diffuse output:
@@ -83,7 +91,8 @@ jobs:
issue-number: ${{ github.event.pull_request.number }}
token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
# gh api repos/actions/upload-artifact/commits/v7 --jq '.sha'
with:
name: diffuse-output
path: ${{ steps.diffuse.outputs.diff-file }}
+2 -1
View File
@@ -11,7 +11,8 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
# gh api repos/actions/checkout/commits/v6 --jq '.sha'
- name: Build image
run: |
cd reproducible-builds
+38
View File
@@ -0,0 +1,38 @@
name: Mark stale issues and PRs
on:
schedule:
- cron: '0 2 * * *' # daily at 02:00 UTC
workflow_dispatch:
jobs:
stale:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
actions: write
steps:
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10
# gh api repos/actions/stale/commits/v10 --jq '.sha'
with:
days-before-stale: 60
days-before-close: 7
exempt-issue-labels: 'acknowledged'
exempt-pr-labels: 'acknowledged'
stale-issue-label: 'wontfix'
stale-pr-label: 'wontfix'
stale-issue-message: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions!
stale-pr-message: >
This pull request has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions!
close-issue-message: >
This issue has been closed due to inactivity.
close-pr-message: >
This pull request has been closed due to inactivity.
operations-per-run: 150
+2 -2
View File
@@ -1,6 +1,6 @@
# Signal Android
Signal is a simple, powerful, and secure messenger that uses your phone's data connection (WiFi/3G/4G/5G) to communicate securely.
Signal is a simple, powerful, and secure messenger that uses your phone's data connection (WiFi/4G/5G) to communicate securely.
Millions of people use Signal every day for free and instantaneous communication anywhere in the world. Send and receive high-fidelity messages, participate in HD voice/video calls, and explore a growing set of new features that help you stay connected.
@@ -63,7 +63,7 @@ The form and manner of this distribution makes it eligible for export under the
## License
Copyright 2013-2025 Signal Messenger, LLC
Copyright 2013 Signal Messenger, LLC
Licensed under the GNU AGPLv3: https://www.gnu.org/licenses/agpl-3.0.html
+145 -106
View File
@@ -1,7 +1,10 @@
@file:Suppress("UnstableApiUsage")
import com.android.build.api.dsl.ManagedVirtualDevice
import com.android.build.api.artifact.ArtifactTransformationRequest
import com.android.build.api.artifact.SingleArtifact
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension
import java.time.Instant
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
@@ -10,7 +13,6 @@ import java.util.Properties
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
alias(libs.plugins.ktlint)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.kotlinx.serialization)
@@ -22,21 +24,22 @@ plugins {
id("licenses")
}
apply(from = "static-ips.gradle.kts")
val staticIps = Properties().apply { file("static-ips.properties").reader().use { load(it) } }
staticIps.stringPropertyNames().forEach { rootProject.extra[it] = staticIps.getProperty(it) }
val canonicalVersionCode = 1670
val canonicalVersionName = "8.4.1"
val canonicalVersionCode = 1685
val canonicalVersionName = "8.10.0"
val currentHotfixVersion = 0
val maxHotfixVersions = 100
// We don't want versions to ever end in 0 so that they don't conflict with nightly versions
val possibleHotfixVersions = (0 until maxHotfixVersions).toList().filter { it % 10 != 0 }
val debugKeystorePropertiesProvider = providers.of(PropertiesFileValueSource::class.java) {
val debugKeystorePropertiesProvider: Provider<Properties> = providers.of(PropertiesFileValueSource::class.java) {
parameters.file.set(rootProject.layout.projectDirectory.file("keystore.debug.properties"))
}
val languagesProvider = providers.of(LanguageListValueSource::class.java) {
val languagesProvider: Provider<List<String>> = providers.of(LanguageListValueSource::class.java) {
parameters.resDir.set(layout.projectDirectory.dir("src/main/res"))
}
@@ -81,6 +84,21 @@ val selectableVariants = listOf(
"githubProdRelease"
)
// Wire 5.x iterates Android source sets and expects matching Kotlin source sets.
// AGP 9.0's built-in Kotlin doesn't create all source sets automatically.
val kotlinExt = extensions.getByName("kotlin") as KotlinAndroidProjectExtension
android.sourceSets.all {
kotlinExt.sourceSets.findByName(name) ?: kotlinExt.sourceSets.create(name)
}
// AGP 9.0's built-in Kotlin doesn't pick up extra java.srcDir entries from Android
// source sets, so add the testShared dir directly to test/androidTest Kotlin
// compile tasks.
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile::class.java).configureEach {
if (name.contains("UnitTest") || name.contains("AndroidTest")) {
source("$projectDir/src/testShared")
}
}
wire {
kotlin {
javaInterop = true
@@ -92,9 +110,8 @@ wire {
protoPath {
srcDir("${project.rootDir}/lib/libsignal-service/src/main/protowire")
srcDir("${project.rootDir}/lib/archive/src/main/protowire")
}
// Handled by libsignal
prune("signalservice.DecryptionErrorMessage")
}
ktlint {
@@ -105,7 +122,7 @@ android {
namespace = "org.thoughtcrime.securesms"
buildToolsVersion = libs.versions.buildTools.get()
compileSdkVersion = libs.versions.compileSdk.get()
compileSdkVersion(libs.versions.compileSdk.get())
ndkVersion = libs.versions.ndk.get()
flavorDimensions += listOf("distribution", "environment")
@@ -113,13 +130,7 @@ android {
android.bundle.language.enableSplit = false
kotlinOptions {
jvmTarget = libs.versions.kotlinJvmTarget.get()
freeCompilerArgs = listOf("-Xjvm-default=all")
suppressWarnings = true
}
debugKeystorePropertiesProvider.orNull?.let { properties ->
debugKeystorePropertiesProvider.get().takeIf { it.isNotEmpty() }?.let { properties ->
signingConfigs.getByName("debug").apply {
storeFile = file("${project.rootDir}/${properties.getProperty("storeFile")}")
storePassword = properties.getProperty("storePassword")
@@ -136,8 +147,8 @@ android {
}
managedDevices {
devices {
create<ManagedVirtualDevice>("pixel3api30") {
localDevices {
create("pixel3api30") {
device = "Pixel 3"
apiLevel = 30
systemImageSource = "google-atd"
@@ -194,10 +205,6 @@ android {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.4"
}
defaultConfig {
if (currentHotfixVersion >= maxHotfixVersions) {
throw AssertionError("Hotfix version offset is too large!")
@@ -290,7 +297,7 @@ android {
isDefault = true
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android.txt"),
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard/proguard-firebase-messaging.pro",
"proguard/proguard-google-play-services.pro",
"proguard/proguard-jackson.pro",
@@ -307,6 +314,7 @@ android {
"proguard/proguard-retrolambda.pro",
"proguard/proguard-okhttp.pro",
"proguard/proguard-ez-vcard.pro",
"proguard/proguard-dnsjava.pro",
"proguard/proguard.cfg"
)
testProguardFiles(
@@ -479,70 +487,6 @@ android {
lintConfig = rootProject.file("lint.xml")
}
androidComponents {
beforeVariants { variant ->
variant.enable = variant.name in selectableVariants
}
onVariants(selector().all()) { variant: com.android.build.api.variant.ApplicationVariant ->
// Include the test-only library on debug builds.
if (variant.buildType != "instrumentation") {
variant.packaging.jniLibs.excludes.add("**/libsignal_jni_testing.so")
}
// Starting with minSdk 23, Android leaves native libraries uncompressed, which is fine for the Play Store, but not for our self-distributed APKs.
// This reverts it to the legacy behavior, compressing the native libraries, and drastically reducing the APK file size.
if (variant.name.contains("website", ignoreCase = true) || variant.name.contains("github", ignoreCase = true)) {
variant.packaging.jniLibs.useLegacyPackaging.set(true)
}
// Version overrides
if (variant.name.contains("nightly", ignoreCase = true)) {
var tag = getNightlyTagForCurrentCommit()
if (!tag.isNullOrEmpty()) {
if (tag.startsWith("v")) {
tag = tag.substring(1)
}
// We add a multiple of maxHotfixVersions to nightlies to ensure we're always at least that many versions ahead
val nightlyBuffer = (5 * maxHotfixVersions)
val nightlyVersionCode = (canonicalVersionCode * maxHotfixVersions) + (getNightlyBuildNumber(tag) * 10) + nightlyBuffer
variant.outputs.forEach { output ->
output.versionName.set("$tag | ${getLastCommitDateTimeUtc()}")
output.versionCode.set(nightlyVersionCode)
}
}
}
}
onVariants(selector().withBuildType("quickstart")) { variant ->
val environment = variant.flavorName?.let { name ->
when {
name.contains("staging", ignoreCase = true) -> "staging"
name.contains("prod", ignoreCase = true) -> "prod"
else -> "prod"
}
} ?: "prod"
val taskProvider = tasks.register<CopyQuickstartCredentialsTask>("copyQuickstartCredentials${variant.name.capitalize()}") {
if (quickstartCredentialsDir != null) {
inputDir.set(File(quickstartCredentialsDir))
}
filePrefix.set("${environment}_")
}
variant.sources.assets?.addGeneratedSourceDirectory(taskProvider) { it.outputDir }
}
onVariants(selector().withBuildType("benchmark")) { variant ->
val taskProvider = tasks.register<CopyBenchmarkBackupTask>("copyBenchmarkBackup${variant.name.capitalize()}") {
if (benchmarkBackupFile != null) {
inputFile.set(File(benchmarkBackupFile))
}
}
variant.sources.assets?.addGeneratedSourceDirectory(taskProvider) { it.outputDir }
}
}
val releaseDir = "$projectDir/src/release/java"
val debugDir = "$projectDir/src/debug/java"
@@ -564,15 +508,79 @@ android {
manifest.srcFile("$projectDir/src/benchmarkShared/AndroidManifest.xml")
}
}
}
applicationVariants.configureEach {
outputs.configureEach {
if (this is com.android.build.gradle.internal.api.BaseVariantOutputImpl) {
val fileVersionName = versionName.substringBefore(" |")
outputFileName = outputFileName.replace(".apk", "-$fileVersionName.apk")
androidComponents {
beforeVariants { variant ->
variant.enable = variant.name in selectableVariants
}
onVariants(selector().all()) { variant: com.android.build.api.variant.ApplicationVariant ->
// Rename APK to include version name
val renameTask = tasks.register<RenameApkTask>("renameApk${variant.name.replaceFirstChar { it.uppercase() }}")
val renameRequest = variant.artifacts.use(renameTask)
.wiredWithDirectories(RenameApkTask::apkFolder, RenameApkTask::outFolder)
.toTransformMany(SingleArtifact.APK)
renameTask.configure {
transformationRequest.set(renameRequest)
}
// Include the test-only library on debug builds.
if (variant.buildType != "instrumentation") {
variant.packaging.jniLibs.excludes.add("**/libsignal_jni_testing.so")
}
// Starting with minSdk 23, Android leaves native libraries uncompressed, which is fine for the Play Store, but not for our self-distributed APKs.
// This reverts it to the legacy behavior, compressing the native libraries, and drastically reducing the APK file size.
if (variant.name.contains("website", ignoreCase = true) || variant.name.contains("github", ignoreCase = true)) {
variant.packaging.jniLibs.useLegacyPackaging.set(true)
}
// Version overrides
if (variant.name.contains("nightly", ignoreCase = true)) {
var tag = getNightlyTagForCurrentCommit()
if (!tag.isNullOrEmpty()) {
if (tag.startsWith("v")) {
tag = tag.substring(1)
}
// We add a multiple of maxHotfixVersions to nightlies to ensure we're always at least that many versions ahead
val nightlyBuffer = (5 * maxHotfixVersions)
val nightlyVersionCode = (canonicalVersionCode * maxHotfixVersions) + (getNightlyBuildNumber(tag) * 10) + nightlyBuffer
variant.outputs.forEach { output ->
output.versionName.set("$tag | ${getLastCommitDateTimeUtc()}")
output.versionCode.set(nightlyVersionCode)
}
}
}
}
onVariants(selector().withBuildType("quickstart")) { variant ->
val environment = variant.flavorName?.let { name ->
when {
name.contains("staging", ignoreCase = true) -> "staging"
name.contains("prod", ignoreCase = true) -> "prod"
else -> "prod"
}
} ?: "prod"
val taskProvider = tasks.register<CopyQuickstartCredentialsTask>("copyQuickstartCredentials${variant.name.capitalize()}") {
if (quickstartCredentialsDir != null) {
inputDir.set(File(quickstartCredentialsDir))
}
filePrefix.set("${environment}_")
}
variant.sources.assets?.addGeneratedSourceDirectory(taskProvider) { it.outputDir }
}
onVariants(selector().withBuildType("benchmark")) { variant ->
val taskProvider = tasks.register<CopyBenchmarkBackupTask>("copyBenchmarkBackup${variant.name.capitalize()}") {
if (benchmarkBackupFile != null) {
inputFile.set(File(benchmarkBackupFile))
}
}
variant.sources.assets?.addGeneratedSourceDirectory(taskProvider) { it.outputDir }
}
}
baselineProfile {
@@ -589,12 +597,22 @@ baselineProfile {
dexLayoutOptimization = false
}
kotlin {
compilerOptions {
jvmTarget = JvmTarget.fromTarget(libs.versions.kotlinJvmTarget.get())
freeCompilerArgs.addAll("-Xjvm-default=all")
suppressWarnings = true
}
}
dependencies {
lintChecks(project(":lintchecks"))
ktlintRuleset(libs.ktlint.twitter.compose)
coreLibraryDesugaring(libs.android.tools.desugar)
implementation(project(":lib:archive"))
implementation(project(":lib:libsignal-service"))
implementation(project(":lib:network"))
implementation(project(":lib:paging"))
implementation(project(":core:util"))
implementation(project(":lib:glide"))
@@ -613,13 +631,10 @@ dependencies {
implementation(project(":core:models-jvm"))
implementation(project(":feature:camera"))
implementation(project(":feature:registration"))
implementation(project(":lib:apng"))
implementation(libs.androidx.fragment.ktx)
implementation(libs.androidx.appcompat) {
version {
strictly("1.6.1")
}
}
implementation(libs.androidx.appcompat)
implementation(libs.androidx.window.window)
implementation(libs.androidx.window.java)
implementation(libs.androidx.recyclerview)
@@ -675,7 +690,6 @@ dependencies {
implementation(libs.mobilecoin)
implementation(libs.signal.ringrtc)
implementation(libs.leolin.shortcutbadger)
implementation(libs.emilsjolander.stickylistheaders)
implementation(libs.glide.glide)
implementation(libs.roundedimageview)
implementation(libs.materialish.progress)
@@ -686,10 +700,6 @@ dependencies {
implementation(libs.subsampling.scale.image.view) {
exclude(group = "com.android.support", module = "support-annotations")
}
implementation(libs.android.tooltips) {
exclude(group = "com.android.support", module = "appcompat-v7")
}
implementation(libs.stream)
implementation(libs.lottie)
implementation(libs.lottie.compose)
implementation(libs.signal.android.database.sqlcipher)
@@ -744,9 +754,11 @@ dependencies {
}
testImplementation(testLibs.conscrypt.openjdk.uber)
testImplementation(testLibs.mockk)
testImplementation(testFixtures(project(":core:ui")))
testImplementation(testFixtures(project(":lib:libsignal-service")))
testImplementation(testLibs.espresso.core)
testImplementation(testLibs.kotlinx.coroutines.test)
testImplementation(testLibs.sqlite.jdbc)
testImplementation(libs.androidx.compose.ui.test.junit4)
"perfImplementation"(libs.androidx.compose.ui.test.manifest)
@@ -857,7 +869,7 @@ abstract class LanguageListValueSource : ValueSource<List<String>, LanguageListV
}
}
abstract class PropertiesFileValueSource : ValueSource<Properties?, PropertiesFileValueSource.Params> {
abstract class PropertiesFileValueSource : ValueSource<Properties, PropertiesFileValueSource.Params> {
interface Params : ValueSourceParameters {
@get:InputFile
@get:Optional
@@ -865,9 +877,9 @@ abstract class PropertiesFileValueSource : ValueSource<Properties?, PropertiesFi
val file: RegularFileProperty
}
override fun obtain(): Properties? {
override fun obtain(): Properties {
val f: File = parameters.file.asFile.get()
if (!f.exists()) return null
if (!f.exists()) return Properties()
return Properties().apply {
f.inputStream().use { load(it) }
@@ -937,3 +949,30 @@ abstract class CopyBenchmarkBackupTask : DefaultTask() {
backupFile.copyTo(dest.resolve("backup.binproto"), overwrite = true)
}
}
abstract class RenameApkTask : DefaultTask() {
@get:InputFiles
abstract val apkFolder: DirectoryProperty
@get:OutputDirectory
abstract val outFolder: DirectoryProperty
@get:Internal
abstract val transformationRequest: Property<ArtifactTransformationRequest<RenameApkTask>>
@TaskAction
fun rename() {
transformationRequest.get().submit(this) { artifact ->
val originalFile = File(artifact.outputFile)
val versionName = artifact.versionName?.substringBefore(" |")
val newName = if (!versionName.isNullOrEmpty()) {
originalFile.name.replace(".apk", "-$versionName.apk")
} else {
originalFile.name
}
val newFile = File(outFolder.get().asFile, newName)
originalFile.copyTo(newFile, overwrite = true)
newFile
}
}
}
-55
View File
@@ -26454,61 +26454,6 @@
column="7"/>
</issue>
<issue
id="Recycle"
message="This `Cursor` should be freed up after use with `#close()`"
errorLine1=" Cursor mmsCursor = db.query(&quot;mms&quot;, new String[] {&quot;_id&quot;},"
errorLine2=" ~~~~~">
<location
file="src/main/java/org/thoughtcrime/securesms/database/helpers/ClassicOpenHelper.java"
line="298"
column="38"/>
</issue>
<issue
id="Recycle"
message="This `Cursor` should be freed up after use with `#close()`"
errorLine1=" Cursor partCursor = db.query(&quot;part&quot;, new String[] {&quot;_id&quot;, &quot;ct&quot;, &quot;_data&quot;, &quot;encrypted&quot;},"
errorLine2=" ~~~~~">
<location
file="src/main/java/org/thoughtcrime/securesms/database/helpers/ClassicOpenHelper.java"
line="310"
column="32"/>
</issue>
<issue
id="Recycle"
message="This `Cursor` should be freed up after use with `#close()`"
errorLine1=" Cursor threadCursor = db.query(&quot;thread&quot;, new String[] {&quot;_id&quot;}, null, null, null, null, null);"
errorLine2=" ~~~~~">
<location
file="src/main/java/org/thoughtcrime/securesms/database/helpers/ClassicOpenHelper.java"
line="708"
column="32"/>
</issue>
<issue
id="Recycle"
message="This `Cursor` should be freed up after use with `#close()`"
errorLine1=" Cursor cursor = db.rawQuery(&quot;SELECT DISTINCT date AS date_received, status, &quot; +"
errorLine2=" ~~~~~~~~">
<location
file="src/main/java/org/thoughtcrime/securesms/database/helpers/ClassicOpenHelper.java"
line="713"
column="28"/>
</issue>
<issue
id="Recycle"
message="This `Cursor` should be freed up after use with `#close()`"
errorLine1=" cursor = db.query(&quot;mms&quot;, new String[] {&quot;_id&quot;, &quot;network_failures&quot;}, &quot;network_failures IS NOT NULL&quot;, null, null, null, null);"
errorLine2=" ~~~~~">
<location
file="src/main/java/org/thoughtcrime/securesms/database/helpers/ClassicOpenHelper.java"
line="1037"
column="19"/>
</issue>
<issue
id="ObsoleteSdkInt"
message="Unnecessary; SDK_INT is always >= 21"
+4
View File
@@ -0,0 +1,4 @@
# dnsjava references desktop/server-only classes that are absent on Android.
-dontwarn com.sun.jna.**
-dontwarn javax.naming.**
-dontwarn lombok.Generated
@@ -13,6 +13,8 @@ import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.signal.archive.proto.Frame
import org.signal.archive.stream.PlainTextBackupReader
import org.signal.core.models.ServiceId
import org.signal.core.util.Base64
import org.signal.core.util.logging.Log
@@ -20,8 +22,6 @@ import org.signal.core.util.readFully
import org.signal.libsignal.messagebackup.ComparableBackup
import org.signal.libsignal.messagebackup.MessageBackup
import org.signal.libsignal.zkgroup.profiles.ProfileKey
import org.thoughtcrime.securesms.backup.v2.proto.Frame
import org.thoughtcrime.securesms.backup.v2.stream.PlainTextBackupReader
import org.thoughtcrime.securesms.database.KeyValueDatabase
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.keyvalue.SignalStore
@@ -358,5 +358,9 @@ class V2ConversationItemShapeTest {
override fun onToggleVote(poll: PollRecord, pollOption: PollOption, isChecked: Boolean) = Unit
override fun onViewPinnedMessage(messageId: Long) = Unit
override fun onExpandEvents(messageId: Long, itemView: View, collapsedSize: Int) = Unit
override fun onCollapseEvents(messageId: Long, itemView: View, collapsedSize: Int) = Unit
}
}
@@ -1,541 +0,0 @@
package org.thoughtcrime.securesms.database
import android.app.Application
import androidx.test.ext.junit.runners.AndroidJUnit4
import net.zetetic.database.sqlcipher.SQLiteDatabase
import net.zetetic.database.sqlcipher.SQLiteOpenHelper
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.signal.core.util.ForeignKeyConstraint
import org.signal.core.util.Index
import org.signal.core.util.getForeignKeys
import org.signal.core.util.getIndexes
import org.signal.core.util.readToList
import org.signal.core.util.requireNonNullString
import org.thoughtcrime.securesms.database.helpers.SignalDatabaseMigrations
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.testing.SignalActivityRule
import org.thoughtcrime.securesms.database.SQLiteDatabase as SignalSQLiteDatabase
/**
* A test that guarantees that a freshly-created database looks the same as one that went through the upgrade path.
*/
@RunWith(AndroidJUnit4::class)
class DatabaseConsistencyTest {
@get:Rule
val harness = SignalActivityRule()
@Test
fun testUpgradeConsistency() {
val currentVersionStatements = SignalDatabase.rawDatabase.getAllCreateStatements()
val testHelper = InMemoryTestHelper(AppDependencies.application).also {
it.onUpgrade(it.writableDatabase, 181, SignalDatabaseMigrations.DATABASE_VERSION)
}
val upgradedStatements = testHelper.readableDatabase.getAllCreateStatements()
if (currentVersionStatements != upgradedStatements) {
var message = "\n"
val currentByName = currentVersionStatements.associateBy { it.name }
val upgradedByName = upgradedStatements.associateBy { it.name }
if (currentByName.keys != upgradedByName.keys) {
val exclusiveToCurrent = currentByName.keys - upgradedByName.keys
val exclusiveToUpgrade = upgradedByName.keys - currentByName.keys
message += "SQL entities exclusive to the newly-created database: $exclusiveToCurrent\n"
message += "SQL entities exclusive to the upgraded database: $exclusiveToUpgrade\n\n"
} else {
for (currentEntry in currentByName) {
val upgradedValue: Statement = upgradedByName[currentEntry.key]!!
if (upgradedValue.sql != currentEntry.value.sql) {
message += "Statement differed:\n"
message += "newly-created:\n"
message += "${currentEntry.value.sql}\n\n"
message += "upgraded:\n"
message += "${upgradedValue.sql}\n\n"
}
}
}
assertTrue(message, false)
}
}
@Test
fun testForeignKeyIndexCoverage() {
/** We may deem certain indexes non-critical if deletion frequency is low or table size is small. */
val ignoredColumns: List<Pair<String, String>> = listOf(
StorySendTable.TABLE_NAME to StorySendTable.DISTRIBUTION_ID
)
val foreignKeys: List<ForeignKeyConstraint> = SignalDatabase.rawDatabase.getForeignKeys()
val indexesByFirstColumn: List<Index> = SignalDatabase.rawDatabase.getIndexes()
val notFound: List<Pair<String, String>> = foreignKeys
.filterNot { ignoredColumns.contains(it.table to it.column) }
.filterNot { foreignKey ->
indexesByFirstColumn.hasPrimaryIndexFor(foreignKey.table, foreignKey.column)
}
.map { it.table to it.column }
assertTrue("Missing indexes to cover: $notFound", notFound.isEmpty())
}
private fun List<Index>.hasPrimaryIndexFor(table: String, column: String): Boolean {
return this.any { index -> index.table == table && index.columns[0] == column }
}
private data class Statement(
val name: String,
val sql: String
)
private fun SQLiteDatabase.getAllCreateStatements(): List<Statement> {
return this.rawQuery("SELECT name, sql FROM sqlite_schema WHERE sql NOT NULL AND name != 'sqlite_sequence'")
.readToList { cursor ->
Statement(
name = cursor.requireNonNullString("name"),
sql = cursor.requireNonNullString("sql").normalizeSql()
)
}
.filterNot { it.name.startsWith("sqlite_stat") }
.sortedBy { it.name }
}
private fun String.normalizeSql(): String {
return this
.split("\n")
.map { it.trim() }
.joinToString(separator = " ")
.replace(Regex.fromLiteral(" ,"), ",")
.replace(",([^\\s])".toRegex(), ", $1")
.replace(Regex("\\s+"), " ")
.replace(Regex.fromLiteral("( "), "(")
.replace(Regex.fromLiteral(" )"), ")")
.replace(Regex("CREATE TABLE \"([a-zA-Z_]+)\""), "CREATE TABLE $1") // for some reason SQLite will wrap table names in quotes for upgraded tables. This unwraps them.
}
private class InMemoryTestHelper(private val application: Application) : SQLiteOpenHelper(application, null, null, 1) {
override fun onCreate(db: SQLiteDatabase) {
for (statement in SNAPSHOT_V181) {
db.execSQL(statement.sql)
}
}
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
SignalDatabaseMigrations.migrate(application, SignalSQLiteDatabase(db), 181, SignalDatabaseMigrations.DATABASE_VERSION)
}
/**
* This is the list of statements that existed at version 181. Never change this.
*/
private val SNAPSHOT_V181 = listOf(
Statement(
name = "message",
sql = "CREATE TABLE message (\n _id INTEGER PRIMARY KEY AUTOINCREMENT,\n date_sent INTEGER NOT NULL,\n date_received INTEGER NOT NULL,\n date_server INTEGER DEFAULT -1,\n thread_id INTEGER NOT NULL REFERENCES thread (_id) ON DELETE CASCADE,\n recipient_id INTEGER NOT NULL REFERENCES recipient (_id) ON DELETE CASCADE,\n recipient_device_id INTEGER,\n type INTEGER NOT NULL,\n body TEXT,\n read INTEGER DEFAULT 0,\n ct_l TEXT,\n exp INTEGER,\n m_type INTEGER,\n m_size INTEGER,\n st INTEGER,\n tr_id TEXT,\n subscription_id INTEGER DEFAULT -1, \n receipt_timestamp INTEGER DEFAULT -1, \n delivery_receipt_count INTEGER DEFAULT 0, \n read_receipt_count INTEGER DEFAULT 0, \n viewed_receipt_count INTEGER DEFAULT 0,\n mismatched_identities TEXT DEFAULT NULL,\n network_failures TEXT DEFAULT NULL,\n expires_in INTEGER DEFAULT 0,\n expire_started INTEGER DEFAULT 0,\n notified INTEGER DEFAULT 0,\n quote_id INTEGER DEFAULT 0,\n quote_author INTEGER DEFAULT 0,\n quote_body TEXT DEFAULT NULL,\n quote_missing INTEGER DEFAULT 0,\n quote_mentions BLOB DEFAULT NULL,\n quote_type INTEGER DEFAULT 0,\n shared_contacts TEXT DEFAULT NULL,\n unidentified INTEGER DEFAULT 0,\n link_previews TEXT DEFAULT NULL,\n view_once INTEGER DEFAULT 0,\n reactions_unread INTEGER DEFAULT 0,\n reactions_last_seen INTEGER DEFAULT -1,\n remote_deleted INTEGER DEFAULT 0,\n mentions_self INTEGER DEFAULT 0,\n notified_timestamp INTEGER DEFAULT 0,\n server_guid TEXT DEFAULT NULL,\n message_ranges BLOB DEFAULT NULL,\n story_type INTEGER DEFAULT 0,\n parent_story_id INTEGER DEFAULT 0,\n export_state BLOB DEFAULT NULL,\n exported INTEGER DEFAULT 0,\n scheduled_date INTEGER DEFAULT -1\n )"
),
Statement(
name = "part",
sql = "CREATE TABLE part (_id INTEGER PRIMARY KEY, mid INTEGER, seq INTEGER DEFAULT 0, ct TEXT, name TEXT, chset INTEGER, cd TEXT, fn TEXT, cid TEXT, cl TEXT, ctt_s INTEGER, ctt_t TEXT, encrypted INTEGER, pending_push INTEGER, _data TEXT, data_size INTEGER, file_name TEXT, unique_id INTEGER NOT NULL, digest BLOB, fast_preflight_id TEXT, voice_note INTEGER DEFAULT 0, borderless INTEGER DEFAULT 0, video_gif INTEGER DEFAULT 0, data_random BLOB, quote INTEGER DEFAULT 0, width INTEGER DEFAULT 0, height INTEGER DEFAULT 0, caption TEXT DEFAULT NULL, sticker_pack_id TEXT DEFAULT NULL, sticker_pack_key DEFAULT NULL, sticker_id INTEGER DEFAULT -1, sticker_emoji STRING DEFAULT NULL, data_hash TEXT DEFAULT NULL, blur_hash TEXT DEFAULT NULL, transform_properties TEXT DEFAULT NULL, transfer_file TEXT DEFAULT NULL, display_order INTEGER DEFAULT 0, upload_timestamp INTEGER DEFAULT 0, cdn_number INTEGER DEFAULT 0)"
),
Statement(
name = "thread",
sql = "CREATE TABLE thread (\n _id INTEGER PRIMARY KEY AUTOINCREMENT, \n date INTEGER DEFAULT 0, \n meaningful_messages INTEGER DEFAULT 0,\n recipient_id INTEGER NOT NULL UNIQUE REFERENCES recipient (_id) ON DELETE CASCADE,\n read INTEGER DEFAULT 1, \n type INTEGER DEFAULT 0, \n error INTEGER DEFAULT 0, \n snippet TEXT, \n snippet_type INTEGER DEFAULT 0, \n snippet_uri TEXT DEFAULT NULL, \n snippet_content_type TEXT DEFAULT NULL, \n snippet_extras TEXT DEFAULT NULL, \n unread_count INTEGER DEFAULT 0, \n archived INTEGER DEFAULT 0, \n status INTEGER DEFAULT 0, \n delivery_receipt_count INTEGER DEFAULT 0, \n read_receipt_count INTEGER DEFAULT 0, \n expires_in INTEGER DEFAULT 0, \n last_seen INTEGER DEFAULT 0, \n has_sent INTEGER DEFAULT 0, \n last_scrolled INTEGER DEFAULT 0, \n pinned INTEGER DEFAULT 0, \n unread_self_mention_count INTEGER DEFAULT 0\n)"
),
Statement(
name = "identities",
sql = "CREATE TABLE identities (\n _id INTEGER PRIMARY KEY AUTOINCREMENT, \n address INTEGER UNIQUE, \n identity_key TEXT, \n first_use INTEGER DEFAULT 0, \n timestamp INTEGER DEFAULT 0, \n verified INTEGER DEFAULT 0, \n nonblocking_approval INTEGER DEFAULT 0\n )"
),
Statement(
name = "drafts",
sql = "CREATE TABLE drafts (\n _id INTEGER PRIMARY KEY, \n thread_id INTEGER, \n type TEXT, \n value TEXT\n )"
),
Statement(
name = "push",
sql = "CREATE TABLE push (_id INTEGER PRIMARY KEY, type INTEGER, source TEXT, source_uuid TEXT, device_id INTEGER, body TEXT, content TEXT, timestamp INTEGER, server_timestamp INTEGER DEFAULT 0, server_delivered_timestamp INTEGER DEFAULT 0, server_guid TEXT DEFAULT NULL)"
),
Statement(
name = "groups",
sql = "CREATE TABLE groups (\n _id INTEGER PRIMARY KEY, \n group_id TEXT, \n recipient_id INTEGER,\n title TEXT,\n avatar_id INTEGER, \n avatar_key BLOB,\n avatar_content_type TEXT, \n avatar_relay TEXT,\n timestamp INTEGER,\n active INTEGER DEFAULT 1,\n avatar_digest BLOB, \n mms INTEGER DEFAULT 0, \n master_key BLOB, \n revision BLOB, \n decrypted_group BLOB, \n expected_v2_id TEXT DEFAULT NULL, \n former_v1_members TEXT DEFAULT NULL, \n distribution_id TEXT DEFAULT NULL, \n display_as_story INTEGER DEFAULT 0, \n auth_service_id TEXT DEFAULT NULL, \n last_force_update_timestamp INTEGER DEFAULT 0\n )"
),
Statement(
name = "group_membership",
sql = "CREATE TABLE group_membership ( _id INTEGER PRIMARY KEY, group_id TEXT NOT NULL, recipient_id INTEGER NOT NULL, UNIQUE(group_id, recipient_id) )"
),
Statement(
name = "recipient",
sql = "CREATE TABLE recipient (\n _id INTEGER PRIMARY KEY AUTOINCREMENT,\n uuid TEXT UNIQUE DEFAULT NULL,\n username TEXT UNIQUE DEFAULT NULL,\n phone TEXT UNIQUE DEFAULT NULL,\n email TEXT UNIQUE DEFAULT NULL,\n group_id TEXT UNIQUE DEFAULT NULL,\n group_type INTEGER DEFAULT 0,\n blocked INTEGER DEFAULT 0,\n message_ringtone TEXT DEFAULT NULL, \n message_vibrate INTEGER DEFAULT 0, \n call_ringtone TEXT DEFAULT NULL, \n call_vibrate INTEGER DEFAULT 0, \n notification_channel TEXT DEFAULT NULL, \n mute_until INTEGER DEFAULT 0, \n color TEXT DEFAULT NULL, \n seen_invite_reminder INTEGER DEFAULT 0,\n default_subscription_id INTEGER DEFAULT -1,\n message_expiration_time INTEGER DEFAULT 0,\n registered INTEGER DEFAULT 0,\n system_given_name TEXT DEFAULT NULL, \n system_family_name TEXT DEFAULT NULL, \n system_display_name TEXT DEFAULT NULL, \n system_photo_uri TEXT DEFAULT NULL, \n system_phone_label TEXT DEFAULT NULL, \n system_phone_type INTEGER DEFAULT -1, \n system_contact_uri TEXT DEFAULT NULL, \n system_info_pending INTEGER DEFAULT 0, \n profile_key TEXT DEFAULT NULL, \n profile_key_credential TEXT DEFAULT NULL, \n signal_profile_name TEXT DEFAULT NULL, \n profile_family_name TEXT DEFAULT NULL, \n profile_joined_name TEXT DEFAULT NULL, \n signal_profile_avatar TEXT DEFAULT NULL, \n profile_sharing INTEGER DEFAULT 0, \n last_profile_fetch INTEGER DEFAULT 0, \n unidentified_access_mode INTEGER DEFAULT 0, \n force_sms_selection INTEGER DEFAULT 0, \n storage_service_key TEXT UNIQUE DEFAULT NULL, \n mention_setting INTEGER DEFAULT 0, \n storage_proto TEXT DEFAULT NULL,\n capabilities INTEGER DEFAULT 0,\n last_session_reset BLOB DEFAULT NULL,\n wallpaper BLOB DEFAULT NULL,\n wallpaper_file TEXT DEFAULT NULL,\n about TEXT DEFAULT NULL,\n about_emoji TEXT DEFAULT NULL,\n extras BLOB DEFAULT NULL,\n groups_in_common INTEGER DEFAULT 0,\n chat_colors BLOB DEFAULT NULL,\n custom_chat_colors_id INTEGER DEFAULT 0,\n badges BLOB DEFAULT NULL,\n pni TEXT DEFAULT NULL,\n distribution_list_id INTEGER DEFAULT NULL,\n needs_pni_signature INTEGER DEFAULT 0,\n unregistered_timestamp INTEGER DEFAULT 0,\n hidden INTEGER DEFAULT 0,\n reporting_token BLOB DEFAULT NULL,\n system_nickname TEXT DEFAULT NULL\n)"
),
Statement(
name = "group_receipts",
sql = "CREATE TABLE group_receipts (\n _id INTEGER PRIMARY KEY, \n mms_id INTEGER, \n address INTEGER, \n status INTEGER, \n timestamp INTEGER, \n unidentified INTEGER DEFAULT 0\n )"
),
Statement(
name = "one_time_prekeys",
sql = "CREATE TABLE one_time_prekeys (\n _id INTEGER PRIMARY KEY,\n account_id TEXT NOT NULL,\n key_id INTEGER UNIQUE, \n public_key TEXT NOT NULL, \n private_key TEXT NOT NULL,\n UNIQUE(account_id, key_id)\n )"
),
Statement(
name = "signed_prekeys",
sql = "CREATE TABLE signed_prekeys (\n _id INTEGER PRIMARY KEY,\n account_id TEXT NOT NULL,\n key_id INTEGER UNIQUE, \n public_key TEXT NOT NULL,\n private_key TEXT NOT NULL,\n signature TEXT NOT NULL, \n timestamp INTEGER DEFAULT 0,\n UNIQUE(account_id, key_id)\n )"
),
Statement(
name = "sessions",
sql = "CREATE TABLE sessions (\n _id INTEGER PRIMARY KEY AUTOINCREMENT,\n account_id TEXT NOT NULL,\n address TEXT NOT NULL,\n device INTEGER NOT NULL,\n record BLOB NOT NULL,\n UNIQUE(account_id, address, device)\n )"
),
Statement(
name = "sender_keys",
sql = "CREATE TABLE sender_keys (\n _id INTEGER PRIMARY KEY AUTOINCREMENT, \n address TEXT NOT NULL, \n device INTEGER NOT NULL, \n distribution_id TEXT NOT NULL,\n record BLOB NOT NULL, \n created_at INTEGER NOT NULL, \n UNIQUE(address,device, distribution_id) ON CONFLICT REPLACE\n )"
),
Statement(
name = "sender_key_shared",
sql = "CREATE TABLE sender_key_shared (\n _id INTEGER PRIMARY KEY AUTOINCREMENT, \n distribution_id TEXT NOT NULL, \n address TEXT NOT NULL, \n device INTEGER NOT NULL, \n timestamp INTEGER DEFAULT 0, \n UNIQUE(distribution_id,address, device) ON CONFLICT REPLACE\n )"
),
Statement(
name = "pending_retry_receipts",
sql = "CREATE TABLE pending_retry_receipts(_id INTEGER PRIMARY KEY AUTOINCREMENT, author TEXT NOT NULL, device INTEGER NOT NULL, sent_timestamp INTEGER NOT NULL, received_timestamp TEXT NOT NULL, thread_id INTEGER NOT NULL, UNIQUE(author,sent_timestamp) ON CONFLICT REPLACE)"
),
Statement(
name = "sticker",
sql = "CREATE TABLE sticker (_id INTEGER PRIMARY KEY AUTOINCREMENT, pack_id TEXT NOT NULL, pack_key TEXT NOT NULL, pack_title TEXT NOT NULL, pack_author TEXT NOT NULL, sticker_id INTEGER, cover INTEGER, pack_order INTEGER, emoji TEXT NOT NULL, content_type TEXT DEFAULT NULL, last_used INTEGER, installed INTEGER,file_path TEXT NOT NULL, file_length INTEGER, file_random BLOB, UNIQUE(pack_id, sticker_id, cover) ON CONFLICT IGNORE)"
),
Statement(
name = "storage_key",
sql = "CREATE TABLE storage_key (_id INTEGER PRIMARY KEY AUTOINCREMENT, type INTEGER, key TEXT UNIQUE)"
),
Statement(
name = "mention",
sql = "CREATE TABLE mention(_id INTEGER PRIMARY KEY AUTOINCREMENT, thread_id INTEGER, message_id INTEGER, recipient_id INTEGER, range_start INTEGER, range_length INTEGER)"
),
Statement(
name = "payments",
sql = "CREATE TABLE payments(_id INTEGER PRIMARY KEY, uuid TEXT DEFAULT NULL, recipient INTEGER DEFAULT 0, recipient_address TEXT DEFAULT NULL, timestamp INTEGER, note TEXT DEFAULT NULL, direction INTEGER, state INTEGER, failure_reason INTEGER, amount BLOB NOT NULL, fee BLOB NOT NULL, transaction_record BLOB DEFAULT NULL, receipt BLOB DEFAULT NULL, payment_metadata BLOB DEFAULT NULL, receipt_public_key TEXT DEFAULT NULL, block_index INTEGER DEFAULT 0, block_timestamp INTEGER DEFAULT 0, seen INTEGER, UNIQUE(uuid) ON CONFLICT ABORT)"
),
Statement(
name = "chat_colors",
sql = "CREATE TABLE chat_colors (\n _id INTEGER PRIMARY KEY AUTOINCREMENT,\n chat_colors BLOB\n)"
),
Statement(
name = "emoji_search",
sql = "CREATE TABLE emoji_search (\n _id INTEGER PRIMARY KEY,\n label TEXT NOT NULL,\n emoji TEXT NOT NULL,\n rank INTEGER DEFAULT 2147483647 \n )"
),
Statement(
name = "avatar_picker",
sql = "CREATE TABLE avatar_picker (\n _id INTEGER PRIMARY KEY AUTOINCREMENT,\n last_used INTEGER DEFAULT 0,\n group_id TEXT DEFAULT NULL,\n avatar BLOB NOT NULL\n)"
),
Statement(
name = "group_call_ring",
sql = "CREATE TABLE group_call_ring (\n _id INTEGER PRIMARY KEY,\n ring_id INTEGER UNIQUE,\n date_received INTEGER,\n ring_state INTEGER\n)"
),
Statement(
name = "reaction",
sql = "CREATE TABLE reaction (\n _id INTEGER PRIMARY KEY,\n message_id INTEGER NOT NULL REFERENCES message (_id) ON DELETE CASCADE,\n author_id INTEGER NOT NULL REFERENCES recipient (_id) ON DELETE CASCADE,\n emoji TEXT NOT NULL,\n date_sent INTEGER NOT NULL,\n date_received INTEGER NOT NULL,\n UNIQUE(message_id, author_id) ON CONFLICT REPLACE\n)"
),
Statement(
name = "donation_receipt",
sql = "CREATE TABLE donation_receipt (\n _id INTEGER PRIMARY KEY AUTOINCREMENT,\n receipt_type TEXT NOT NULL,\n receipt_date INTEGER NOT NULL,\n amount TEXT NOT NULL,\n currency TEXT NOT NULL,\n subscription_level INTEGER NOT NULL\n)"
),
Statement(
name = "story_sends",
sql = "CREATE TABLE story_sends (\n _id INTEGER PRIMARY KEY,\n message_id INTEGER NOT NULL REFERENCES message (_id) ON DELETE CASCADE,\n recipient_id INTEGER NOT NULL REFERENCES recipient (_id) ON DELETE CASCADE,\n sent_timestamp INTEGER NOT NULL,\n allows_replies INTEGER NOT NULL,\n distribution_id TEXT NOT NULL REFERENCES distribution_list (distribution_id) ON DELETE CASCADE\n)"
),
Statement(
name = "cds",
sql = "CREATE TABLE cds (\n _id INTEGER PRIMARY KEY,\n e164 TEXT NOT NULL UNIQUE ON CONFLICT IGNORE,\n last_seen_at INTEGER DEFAULT 0\n )"
),
Statement(
name = "remote_megaphone",
sql = "CREATE TABLE remote_megaphone (\n _id INTEGER PRIMARY KEY,\n uuid TEXT UNIQUE NOT NULL,\n priority INTEGER NOT NULL,\n countries TEXT,\n minimum_version INTEGER NOT NULL,\n dont_show_before INTEGER NOT NULL,\n dont_show_after INTEGER NOT NULL,\n show_for_days INTEGER NOT NULL,\n conditional_id TEXT,\n primary_action_id TEXT,\n secondary_action_id TEXT,\n image_url TEXT,\n image_uri TEXT DEFAULT NULL,\n title TEXT NOT NULL,\n body TEXT NOT NULL,\n primary_action_text TEXT,\n secondary_action_text TEXT,\n shown_at INTEGER DEFAULT 0,\n finished_at INTEGER DEFAULT 0,\n primary_action_data TEXT DEFAULT NULL,\n secondary_action_data TEXT DEFAULT NULL,\n snoozed_at INTEGER DEFAULT 0,\n seen_count INTEGER DEFAULT 0\n)"
),
Statement(
name = "pending_pni_signature_message",
sql = "CREATE TABLE pending_pni_signature_message (\n _id INTEGER PRIMARY KEY,\n recipient_id INTEGER NOT NULL REFERENCES recipient (_id) ON DELETE CASCADE,\n sent_timestamp INTEGER NOT NULL,\n device_id INTEGER NOT NULL\n )"
),
Statement(
name = "call",
sql = "CREATE TABLE call (\n _id INTEGER PRIMARY KEY,\n call_id INTEGER NOT NULL UNIQUE,\n message_id INTEGER NOT NULL REFERENCES message (_id) ON DELETE CASCADE,\n peer INTEGER NOT NULL REFERENCES recipient (_id) ON DELETE CASCADE,\n type INTEGER NOT NULL,\n direction INTEGER NOT NULL,\n event INTEGER NOT NULL\n)"
),
Statement(
name = "message_fts",
sql = "CREATE VIRTUAL TABLE message_fts USING fts5(body, thread_id UNINDEXED, content=message, content_rowid=_id)"
),
Statement(
name = "remapped_recipients",
sql = "CREATE TABLE remapped_recipients (\n _id INTEGER PRIMARY KEY AUTOINCREMENT, \n old_id INTEGER UNIQUE, \n new_id INTEGER\n )"
),
Statement(
name = "remapped_threads",
sql = "CREATE TABLE remapped_threads (\n _id INTEGER PRIMARY KEY AUTOINCREMENT, \n old_id INTEGER UNIQUE, \n new_id INTEGER\n )"
),
Statement(
name = "msl_payload",
sql = "CREATE TABLE msl_payload (\n _id INTEGER PRIMARY KEY,\n date_sent INTEGER NOT NULL,\n content BLOB NOT NULL,\n content_hint INTEGER NOT NULL,\n urgent INTEGER NOT NULL DEFAULT 1\n )"
),
Statement(
name = "msl_recipient",
sql = "CREATE TABLE msl_recipient (\n _id INTEGER PRIMARY KEY,\n payload_id INTEGER NOT NULL REFERENCES msl_payload (_id) ON DELETE CASCADE,\n recipient_id INTEGER NOT NULL, \n device INTEGER NOT NULL\n )"
),
Statement(
name = "msl_message",
sql = "CREATE TABLE msl_message (\n _id INTEGER PRIMARY KEY,\n payload_id INTEGER NOT NULL REFERENCES msl_payload (_id) ON DELETE CASCADE,\n message_id INTEGER NOT NULL\n )"
),
Statement(
name = "notification_profile",
sql = "CREATE TABLE notification_profile (\n _id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT NOT NULL UNIQUE,\n emoji TEXT NOT NULL,\n color TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n allow_all_calls INTEGER NOT NULL DEFAULT 0,\n allow_all_mentions INTEGER NOT NULL DEFAULT 0\n)"
),
Statement(
name = "notification_profile_schedule",
sql = "CREATE TABLE notification_profile_schedule (\n _id INTEGER PRIMARY KEY AUTOINCREMENT,\n notification_profile_id INTEGER NOT NULL REFERENCES notification_profile (_id) ON DELETE CASCADE,\n enabled INTEGER NOT NULL DEFAULT 0,\n start INTEGER NOT NULL,\n end INTEGER NOT NULL,\n days_enabled TEXT NOT NULL\n)"
),
Statement(
name = "notification_profile_allowed_members",
sql = "CREATE TABLE notification_profile_allowed_members (\n _id INTEGER PRIMARY KEY AUTOINCREMENT,\n notification_profile_id INTEGER NOT NULL REFERENCES notification_profile (_id) ON DELETE CASCADE,\n recipient_id INTEGER NOT NULL,\n UNIQUE(notification_profile_id, recipient_id) ON CONFLICT REPLACE\n)"
),
Statement(
name = "distribution_list",
sql = "CREATE TABLE distribution_list (\n _id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT UNIQUE NOT NULL,\n distribution_id TEXT UNIQUE NOT NULL,\n recipient_id INTEGER UNIQUE REFERENCES recipient (_id),\n allows_replies INTEGER DEFAULT 1,\n deletion_timestamp INTEGER DEFAULT 0,\n is_unknown INTEGER DEFAULT 0,\n privacy_mode INTEGER DEFAULT 0\n )"
),
Statement(
name = "distribution_list_member",
sql = "CREATE TABLE distribution_list_member (\n _id INTEGER PRIMARY KEY AUTOINCREMENT,\n list_id INTEGER NOT NULL REFERENCES distribution_list (_id) ON DELETE CASCADE,\n recipient_id INTEGER NOT NULL REFERENCES recipient (_id),\n privacy_mode INTEGER DEFAULT 0\n )"
),
Statement(
name = "recipient_group_type_index",
sql = "CREATE INDEX recipient_group_type_index ON recipient (group_type)"
),
Statement(
name = "recipient_pni_index",
sql = "CREATE UNIQUE INDEX recipient_pni_index ON recipient (pni)"
),
Statement(
name = "recipient_service_id_profile_key",
sql = "CREATE INDEX recipient_service_id_profile_key ON recipient (uuid, profile_key) WHERE uuid NOT NULL AND profile_key NOT NULL"
),
Statement(
name = "mms_read_and_notified_and_thread_id_index",
sql = "CREATE INDEX mms_read_and_notified_and_thread_id_index ON message (read, notified, thread_id)"
),
Statement(
name = "mms_type_index",
sql = "CREATE INDEX mms_type_index ON message (type)"
),
Statement(
name = "mms_date_sent_index",
sql = "CREATE INDEX mms_date_sent_index ON message (date_sent, recipient_id, thread_id)"
),
Statement(
name = "mms_date_server_index",
sql = "CREATE INDEX mms_date_server_index ON message (date_server)"
),
Statement(
name = "mms_thread_date_index",
sql = "CREATE INDEX mms_thread_date_index ON message (thread_id, date_received)"
),
Statement(
name = "mms_reactions_unread_index",
sql = "CREATE INDEX mms_reactions_unread_index ON message (reactions_unread)"
),
Statement(
name = "mms_story_type_index",
sql = "CREATE INDEX mms_story_type_index ON message (story_type)"
),
Statement(
name = "mms_parent_story_id_index",
sql = "CREATE INDEX mms_parent_story_id_index ON message (parent_story_id)"
),
Statement(
name = "mms_thread_story_parent_story_scheduled_date_index",
sql = "CREATE INDEX mms_thread_story_parent_story_scheduled_date_index ON message (thread_id, date_received, story_type, parent_story_id, scheduled_date)"
),
Statement(
name = "message_quote_id_quote_author_scheduled_date_index",
sql = "CREATE INDEX message_quote_id_quote_author_scheduled_date_index ON message (quote_id, quote_author, scheduled_date)"
),
Statement(
name = "mms_exported_index",
sql = "CREATE INDEX mms_exported_index ON message (exported)"
),
Statement(
name = "mms_id_type_payment_transactions_index",
sql = "CREATE INDEX mms_id_type_payment_transactions_index ON message (_id,type) WHERE type & 12884901888 != 0"
),
Statement(
name = "part_mms_id_index",
sql = "CREATE INDEX part_mms_id_index ON part (mid)"
),
Statement(
name = "pending_push_index",
sql = "CREATE INDEX pending_push_index ON part (pending_push)"
),
Statement(
name = "part_sticker_pack_id_index",
sql = "CREATE INDEX part_sticker_pack_id_index ON part (sticker_pack_id)"
),
Statement(
name = "part_data_hash_index",
sql = "CREATE INDEX part_data_hash_index ON part (data_hash)"
),
Statement(
name = "part_data_index",
sql = "CREATE INDEX part_data_index ON part (_data)"
),
Statement(
name = "thread_recipient_id_index",
sql = "CREATE INDEX thread_recipient_id_index ON thread (recipient_id)"
),
Statement(
name = "archived_count_index",
sql = "CREATE INDEX archived_count_index ON thread (archived, meaningful_messages)"
),
Statement(
name = "thread_pinned_index",
sql = "CREATE INDEX thread_pinned_index ON thread (pinned)"
),
Statement(
name = "thread_read",
sql = "CREATE INDEX thread_read ON thread (read)"
),
Statement(
name = "draft_thread_index",
sql = "CREATE INDEX draft_thread_index ON drafts (thread_id)"
),
Statement(
name = "group_id_index",
sql = "CREATE UNIQUE INDEX group_id_index ON groups (group_id)"
),
Statement(
name = "group_recipient_id_index",
sql = "CREATE UNIQUE INDEX group_recipient_id_index ON groups (recipient_id)"
),
Statement(
name = "expected_v2_id_index",
sql = "CREATE UNIQUE INDEX expected_v2_id_index ON groups (expected_v2_id)"
),
Statement(
name = "group_distribution_id_index",
sql = "CREATE UNIQUE INDEX group_distribution_id_index ON groups(distribution_id)"
),
Statement(
name = "group_receipt_mms_id_index",
sql = "CREATE INDEX group_receipt_mms_id_index ON group_receipts (mms_id)"
),
Statement(
name = "sticker_pack_id_index",
sql = "CREATE INDEX sticker_pack_id_index ON sticker (pack_id)"
),
Statement(
name = "sticker_sticker_id_index",
sql = "CREATE INDEX sticker_sticker_id_index ON sticker (sticker_id)"
),
Statement(
name = "storage_key_type_index",
sql = "CREATE INDEX storage_key_type_index ON storage_key (type)"
),
Statement(
name = "mention_message_id_index",
sql = "CREATE INDEX mention_message_id_index ON mention (message_id)"
),
Statement(
name = "mention_recipient_id_thread_id_index",
sql = "CREATE INDEX mention_recipient_id_thread_id_index ON mention (recipient_id, thread_id)"
),
Statement(
name = "timestamp_direction_index",
sql = "CREATE INDEX timestamp_direction_index ON payments (timestamp, direction)"
),
Statement(
name = "timestamp_index",
sql = "CREATE INDEX timestamp_index ON payments (timestamp)"
),
Statement(
name = "receipt_public_key_index",
sql = "CREATE UNIQUE INDEX receipt_public_key_index ON payments (receipt_public_key)"
),
Statement(
name = "msl_payload_date_sent_index",
sql = "CREATE INDEX msl_payload_date_sent_index ON msl_payload (date_sent)"
),
Statement(
name = "msl_recipient_recipient_index",
sql = "CREATE INDEX msl_recipient_recipient_index ON msl_recipient (recipient_id, device, payload_id)"
),
Statement(
name = "msl_recipient_payload_index",
sql = "CREATE INDEX msl_recipient_payload_index ON msl_recipient (payload_id)"
),
Statement(
name = "msl_message_message_index",
sql = "CREATE INDEX msl_message_message_index ON msl_message (message_id, payload_id)"
),
Statement(
name = "date_received_index",
sql = "CREATE INDEX date_received_index on group_call_ring (date_received)"
),
Statement(
name = "notification_profile_schedule_profile_index",
sql = "CREATE INDEX notification_profile_schedule_profile_index ON notification_profile_schedule (notification_profile_id)"
),
Statement(
name = "notification_profile_allowed_members_profile_index",
sql = "CREATE INDEX notification_profile_allowed_members_profile_index ON notification_profile_allowed_members (notification_profile_id)"
),
Statement(
name = "donation_receipt_type_index",
sql = "CREATE INDEX donation_receipt_type_index ON donation_receipt (receipt_type)"
),
Statement(
name = "donation_receipt_date_index",
sql = "CREATE INDEX donation_receipt_date_index ON donation_receipt (receipt_date)"
),
Statement(
name = "story_sends_recipient_id_sent_timestamp_allows_replies_index",
sql = "CREATE INDEX story_sends_recipient_id_sent_timestamp_allows_replies_index ON story_sends (recipient_id, sent_timestamp, allows_replies)"
),
Statement(
name = "story_sends_message_id_distribution_id_index",
sql = "CREATE INDEX story_sends_message_id_distribution_id_index ON story_sends (message_id, distribution_id)"
),
Statement(
name = "distribution_list_member_list_id_recipient_id_privacy_mode_index",
sql = "CREATE UNIQUE INDEX distribution_list_member_list_id_recipient_id_privacy_mode_index ON distribution_list_member (list_id, recipient_id, privacy_mode)"
),
Statement(
name = "pending_pni_recipient_sent_device_index",
sql = "CREATE UNIQUE INDEX pending_pni_recipient_sent_device_index ON pending_pni_signature_message (recipient_id, sent_timestamp, device_id)"
),
Statement(
name = "call_call_id_index",
sql = "CREATE INDEX call_call_id_index ON call (call_id)"
),
Statement(
name = "call_message_id_index",
sql = "CREATE INDEX call_message_id_index ON call (message_id)"
),
Statement(
name = "message_ai",
sql = "CREATE TRIGGER message_ai AFTER INSERT ON message BEGIN\n INSERT INTO message_fts(rowid, body, thread_id) VALUES (new._id, new.body, new.thread_id);\n END"
),
Statement(
name = "message_ad",
sql = "CREATE TRIGGER message_ad AFTER DELETE ON message BEGIN\n INSERT INTO message_fts(message_fts, rowid, body, thread_id) VALUES('delete', old._id, old.body, old.thread_id);\n END"
),
Statement(
name = "message_au",
sql = "CREATE TRIGGER message_au AFTER UPDATE ON message BEGIN\n INSERT INTO message_fts(message_fts, rowid, body, thread_id) VALUES('delete', old._id, old.body, old.thread_id);\n INSERT INTO message_fts(rowid, body, thread_id) VALUES (new._id, new.body, new.thread_id);\n END"
),
Statement(
name = "msl_message_delete",
sql = "CREATE TRIGGER msl_message_delete AFTER DELETE ON message \n BEGIN \n \tDELETE FROM msl_payload WHERE _id IN (SELECT payload_id FROM msl_message WHERE message_id = old._id);\n END"
),
Statement(
name = "msl_attachment_delete",
sql = "CREATE TRIGGER msl_attachment_delete AFTER DELETE ON part\n BEGIN\n \tDELETE FROM msl_payload WHERE _id IN (SELECT payload_id FROM msl_message WHERE message_id = old.mid);\n END"
)
)
}
}
@@ -313,7 +313,7 @@ class SmsDatabaseTest_collapseJoinRequestEventsIfPossible {
timestamp = wallClock,
groupId = groupId,
update = updateDescription,
isGroupAdd = false,
isNotifiable = false,
serverGuid = null
)
}
@@ -1,52 +0,0 @@
package org.thoughtcrime.securesms.database
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Assert.assertFalse
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.signal.core.models.ServiceId.ACI
import org.signal.core.util.CursorUtil
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.testing.SignalDatabaseRule
import java.util.UUID
@Suppress("ClassName")
@RunWith(AndroidJUnit4::class)
class ThreadTableTest_recents {
@Rule
@JvmField
val databaseRule = SignalDatabaseRule()
private lateinit var recipient: Recipient
@Before
fun setUp() {
recipient = Recipient.resolved(SignalDatabase.recipients.getOrInsertFromServiceId(ACI.from(UUID.randomUUID())))
}
@Test
fun givenARecentRecipient_whenIBlockAndGetRecents_thenIDoNotExpectToSeeThatRecipient() {
// GIVEN
val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient)
MmsHelper.insert(recipient = recipient, threadId = threadId)
SignalDatabase.threads.update(threadId, true)
// WHEN
SignalDatabase.recipients.setBlocked(recipient.id, true)
val results: MutableList<RecipientId> = SignalDatabase.threads.getRecentConversationList(10, false, false, false, false, false, false).use { cursor ->
val ids = mutableListOf<RecipientId>()
while (cursor.moveToNext()) {
ids.add(RecipientId.from(CursorUtil.requireLong(cursor, ThreadTable.RECIPIENT_ID)))
}
ids
}
// THEN
assertFalse(recipient.id in results)
}
}
@@ -4,12 +4,12 @@ import android.app.Application
import io.mockk.mockk
import io.mockk.spyk
import org.signal.core.util.billing.BillingApi
import org.signal.network.api.ArchiveApi
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess
import org.thoughtcrime.securesms.recipients.LiveRecipientCache
import org.whispersystems.signalservice.api.SignalServiceDataStore
import org.whispersystems.signalservice.api.SignalServiceMessageSender
import org.whispersystems.signalservice.api.account.AccountApi
import org.whispersystems.signalservice.api.archive.ArchiveApi
import org.whispersystems.signalservice.api.attachment.AttachmentApi
import org.whispersystems.signalservice.api.donations.DonationsApi
import org.whispersystems.signalservice.api.keys.KeysApi
@@ -316,7 +316,7 @@ class DataMessageProcessorTest_polls {
private fun insertPoll(allowMultiple: Boolean = true): Long {
val envelope = MessageContentFuzzer.envelope(100)
val pollMessage = IncomingMessage(type = MessageType.NORMAL, from = alice.id, sentTimeMillis = envelope.timestamp!!, serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = 0, groupId = groupId)
val pollMessage = IncomingMessage(type = MessageType.NORMAL, from = alice.id, sentTimeMillis = envelope.clientTimestamp!!, serverTimeMillis = envelope.serverTimestamp!!, receivedTimeMillis = 0, groupId = groupId)
val messageId = SignalDatabase.messages.insertMessageInbox(pollMessage).get()
SignalDatabase.polls.insertPoll("question?", allowMultiple, listOf("a", "b", "c"), alice.id.toLong(), messageId.messageId)
return messageId.messageId
@@ -43,7 +43,7 @@ object MessageContentFuzzer {
*/
fun envelope(timestamp: Long, serverGuid: UUID = UUID.randomUUID()): Envelope {
return Envelope.Builder()
.timestamp(timestamp)
.clientTimestamp(timestamp)
.serverTimestamp(timestamp + 5)
.serverGuidBinary(serverGuid.toByteArray().toByteString())
.build()
@@ -292,7 +292,7 @@ object MessageContentFuzzer {
body = string()
val quoted = quoteAble.random(random)
quote = DataMessage.Quote.Builder().buildWith {
id = quoted.envelope.timestamp
id = quoted.envelope.clientTimestamp
authorAciBinary = quoted.metadata.sourceServiceId.toByteString()
text = quoted.content.dataMessage?.body
attachments(quoted.content.dataMessage?.attachments ?: emptyList())
@@ -304,7 +304,7 @@ object MessageContentFuzzer {
if (random.nextFloat() < 0.1 && quoteAble.isNotEmpty()) {
val quoted = quoteAble.random(random)
quote = DataMessage.Quote.Builder().buildWith {
id = random.nextLong(quoted.envelope.timestamp!! - 1000000, quoted.envelope.timestamp!!)
id = random.nextLong(quoted.envelope.clientTimestamp!! - 1000000, quoted.envelope.clientTimestamp!!)
authorAciBinary = quoted.metadata.sourceServiceId.toByteString()
text = quoted.content.dataMessage?.body
}
@@ -333,7 +333,7 @@ object MessageContentFuzzer {
emoji = emojis.random(random)
remove = false
targetAuthorAciBinary = reactTo.metadata.sourceServiceId.toByteString()
targetSentTimestamp = reactTo.envelope.timestamp
targetSentTimestamp = reactTo.envelope.clientTimestamp
}
}
}
@@ -75,8 +75,8 @@ object MockProvider {
val device = PreKeyResponseItem().apply {
this.deviceId = deviceId
registrationId = KeyHelper.generateRegistrationId(false)
signedPreKey = SignedPreKeyEntity(signedPreKeyRecord.id, signedPreKeyRecord.keyPair.publicKey, signedPreKeyRecord.signature)
preKey = PreKeyEntity(oneTimePreKey.id, oneTimePreKey.keyPair.publicKey)
signedPreKey = SignedPreKeyEntity(signedPreKeyRecord.id.toLong(), signedPreKeyRecord.keyPair.publicKey, signedPreKeyRecord.signature)
preKey = PreKeyEntity(oneTimePreKey.id.toLong(), oneTimePreKey.keyPair.publicKey)
}
return PreKeyResponse().apply {
@@ -212,7 +212,7 @@ class BenchmarkCommandReceiver : BroadcastReceiver() {
verb = "PUT",
path = "/api/v1/message",
id = Random.nextLong(),
headers = listOf("X-Signal-Timestamp: ${this.timestamp}"),
headers = listOf("X-Signal-Timestamp: ${this.serverTimestamp}"),
body = this.encodeByteString()
)
}
@@ -70,8 +70,8 @@ object Generator {
val serverGuid = UUID.randomUUID()
return Envelope.Builder()
.type(Envelope.Type.fromValue(this.type))
.sourceDevice(1)
.timestamp(timestamp)
.sourceDeviceId(1)
.clientTimestamp(timestamp)
.serverTimestamp(timestamp + 1)
.destinationServiceId(destination.toString())
.destinationServiceIdBinary(destination.toByteString())
@@ -74,7 +74,7 @@ class OtherClient(val serviceId: ServiceId, val e164: String, val identityKeyPai
val cipher = SignalServiceCipher(serviceAddress, 1, aciStore, sessionLock, null)
if (!aciStore.containsSession(getAliceProtocolAddress())) {
val sessionBuilder = SignalSessionBuilder(sessionLock, SessionBuilder(aciStore, getAliceProtocolAddress()))
val sessionBuilder = SignalSessionBuilder(sessionLock, SessionBuilder(aciStore, getAliceProtocolAddress(), SignalProtocolAddress(serviceAddress.identifier, 1)))
sessionBuilder.process(getAlicePreKeyBundle())
}
@@ -9,6 +9,7 @@ import org.thoughtcrime.securesms.conversation.ConversationMessage.ConversationM
import org.thoughtcrime.securesms.conversation.v2.data.ConversationElementKey
import org.thoughtcrime.securesms.conversation.v2.data.IncomingTextOnly
import org.thoughtcrime.securesms.conversation.v2.data.OutgoingTextOnly
import org.thoughtcrime.securesms.database.CollapsedState
import org.thoughtcrime.securesms.database.MessageTypes
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
import org.thoughtcrime.securesms.database.model.StoryType
@@ -122,7 +123,10 @@ class ConversationElementGenerator {
false,
0,
null,
null
CollapsedState.NONE,
0,
null,
false
)
val conversationMessage = ConversationMessageFactory.createWithUnresolvedData(
@@ -353,5 +353,13 @@ class InternalConversationTestFragment : Fragment(R.layout.conversation_test_fra
override fun onViewPinnedMessage(messageId: Long) {
Toast.makeText(requireContext(), "Can't touch this.", Toast.LENGTH_SHORT).show()
}
override fun onExpandEvents(messageId: Long, itemView: View, collapsedSize: Int) {
Toast.makeText(requireContext(), "Can't touch this.", Toast.LENGTH_SHORT).show()
}
override fun onCollapseEvents(messageId: Long, itemView: View, collapsedSize: Int) {
Toast.makeText(requireContext(), "Can't touch this.", Toast.LENGTH_SHORT).show()
}
}
}
+15 -1
View File
@@ -458,6 +458,13 @@
android:label="@string/AndroidManifest__select_contacts"
android:windowSoftInputMode="stateHidden" />
<activity
android:name=".search.SingleContactSelectionActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:exported="false"
android:label="@string/AndroidManifest__select_contacts"
android:windowSoftInputMode="stateHidden" />
<activity
android:name=".giph.ui.GiphyActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
@@ -475,7 +482,7 @@
android:windowSoftInputMode="stateAlwaysHidden|adjustNothing" />
<activity
android:name="org.signal.mediasend.MediaSendActivity"
android:name=".mediasend.v3.MediaSendV3Activity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"
android:exported="false"
android:launchMode="singleTop"
@@ -668,6 +675,13 @@
android:theme="@style/TextSecure.DarkNoActionBar"
android:windowSoftInputMode="stateHidden" />
<activity
android:name=".starred.StarredMessagesActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:exported="false"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:windowSoftInputMode="stateHidden" />
<activity
android:name=".mediaoverview.MediaOverviewActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 KiB

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 KiB

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 213 KiB

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 KiB

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 KiB

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 298 KiB

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 KiB

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 94 KiB

File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -62,6 +62,7 @@ import org.thoughtcrime.securesms.jobs.AccountConsistencyWorkerJob;
import org.thoughtcrime.securesms.jobs.BackupRefreshJob;
import org.thoughtcrime.securesms.jobs.BackupSubscriptionCheckJob;
import org.thoughtcrime.securesms.jobs.BuildExpirationConfirmationJob;
import org.thoughtcrime.securesms.jobs.CallingAssetsDownloadJob;
import org.thoughtcrime.securesms.jobs.CheckKeyTransparencyJob;
import org.thoughtcrime.securesms.jobs.CheckServiceReachabilityJob;
import org.thoughtcrime.securesms.jobs.DownloadLatestEmojiDataJob;
@@ -102,12 +103,14 @@ import org.thoughtcrime.securesms.service.MessageBackupListener;
import org.thoughtcrime.securesms.service.RotateSenderCertificateListener;
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
import org.thoughtcrime.securesms.service.webrtc.ActiveCallManager;
import org.thoughtcrime.securesms.service.webrtc.CallingAssets;
import org.thoughtcrime.securesms.service.webrtc.AndroidTelecomUtil;
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
import org.thoughtcrime.securesms.util.AppForegroundObserver;
import org.thoughtcrime.securesms.util.AppStartup;
import org.thoughtcrime.securesms.util.DeviceProperties;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.Environment;
import org.thoughtcrime.securesms.util.RemoteConfig;
import org.thoughtcrime.securesms.util.SignalLocalMetrics;
import org.thoughtcrime.securesms.util.SignalUncaughtExceptionHandler;
@@ -214,7 +217,6 @@ public class ApplicationContext extends Application implements AppForegroundObse
.addNonBlocking(this::ensureProfileUploaded)
.addNonBlocking(() -> AppDependencies.getExpireStoriesManager().scheduleIfNecessary())
.addNonBlocking(BackupRepository::maybeFixAnyDanglingUploadProgress)
.addNonBlocking(BackupRepository::maybeFixAnyDanglingLocalExportProgress)
.addPostRender(() -> AppDependencies.getDeletedCallEventManager().scheduleIfNecessary())
.addPostRender(() -> RateLimitUtil.retryAllRateLimitedMessages(this))
.addPostRender(this::initializeExpiringMessageManager)
@@ -227,6 +229,7 @@ public class ApplicationContext extends Application implements AppForegroundObse
.addPostRender(RetrieveRemoteAnnouncementsJob::enqueue)
.addPostRender(AndroidTelecomUtil::registerPhoneAccount)
.addPostRender(() -> AppDependencies.getJobManager().add(new FontDownloaderJob()))
.addPostRender(() -> AppDependencies.getJobManager().add(new CallingAssetsDownloadJob()))
.addPostRender(CheckServiceReachabilityJob::enqueueIfNecessary)
.addPostRender(GroupV2UpdateSelfProfileKeyJob::enqueueForGroupsIfNecessary)
.addPostRender(StoryOnboardingDownloadJob.Companion::enqueueIfNeeded)
@@ -318,7 +321,7 @@ public class ApplicationContext extends Application implements AppForegroundObse
* This is so we can capture ANR's that happen on boot before the foreground event.
*/
private void startAnrDetector() {
AnrDetector.start(TimeUnit.SECONDS.toMillis(5), RemoteConfig::internalUser, (dumps) -> {
AnrDetector.start(TimeUnit.SECONDS.toMillis(5), () -> RemoteConfig.internalUser() && SignalStore.internal().getAnrDetectionCrashes(), (dumps) -> {
LogDatabase.getInstance(this).anrs().save(System.currentTimeMillis(), dumps);
return Unit.INSTANCE;
});
@@ -401,6 +404,20 @@ public class ApplicationContext extends Application implements AppForegroundObse
AppDependencies.init(this, new ApplicationDependencyProvider(this));
}
AppForegroundObserver.begin();
if (Environment.USE_NEW_REGISTRATION) {
initializeRegistrationDependencies();
}
}
private void initializeRegistrationDependencies() {
org.signal.registration.RegistrationDependencies.Companion.provide(
new org.signal.registration.RegistrationDependencies(
new org.thoughtcrime.securesms.registration.v2.AppRegistrationNetworkController(this, AppDependencies.getPushServiceSocket()),
new org.thoughtcrime.securesms.registration.v2.AppRegistrationStorageController(this),
null
)
);
}
private void initializeFirstEverAppLaunch() {

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