Compare commits

...

227 Commits

Author SHA1 Message Date
Greyson Parrelli
42b0fe7853 Bump version to 5.0.4 2020-12-10 12:36:38 -05:00
Greyson Parrelli
7877f5db2f Updated language translations. 2020-12-10 12:36:38 -05:00
Alex Hart
b972e05660 Auto focus national number field after valid country code in delete fragment. 2020-12-10 12:36:38 -05:00
Greyson Parrelli
23579a9b1d Do not unnecessarily refresh known-unregistered users during migration. 2020-12-10 12:36:38 -05:00
Greyson Parrelli
af99753d47 Trace Application and Activity creates. 2020-12-10 11:45:15 -05:00
Greyson Parrelli
4b2366e537 Bump version to 5.0.3 2020-12-09 17:42:44 -05:00
Greyson Parrelli
bea72c2ee3 Updated language translations. 2020-12-09 17:42:44 -05:00
Greyson Parrelli
32a50fcfad Disable group calling for API 19. 2020-12-09 17:42:44 -05:00
Greyson Parrelli
30fa741365 Make group calling flag hot-swappable. 2020-12-09 17:39:02 -05:00
Greyson Parrelli
bed2544ff4 Don't try to update contacts if you have no permission.
Fixes #10271
2020-12-09 17:07:54 -05:00
Cody Henthorne
5a773de3b1 Handle group call update sync messages. 2020-12-09 16:33:47 -05:00
Alan Evans
924405c8ba Increase uncompressed video attachment size to 500 Mb. 2020-12-09 16:30:42 -04:00
Alan Evans
93e9de3932 Increase stream copy buffer size to 64K. 2020-12-09 16:29:08 -04:00
Alan Evans
a8dd81eace Return optional for telephone number region name for the unknown case to be localized. 2020-12-09 15:47:44 -04:00
Greyson Parrelli
ec8793c6fe Fix rendering issue when deleting the last message in a conversation. 2020-12-09 14:39:22 -05:00
Alex Hart
ffc0a230be Fix country code width on account deletion screen. 2020-12-09 14:09:21 -04:00
Cody Henthorne
5d4922ed8d Show accurate current group call participants in lobby header. 2020-12-09 11:53:59 -05:00
Alan Evans
974c33fe37 Directly reference activity for remove avatar confirmation prompt. 2020-12-09 11:15:48 -04:00
Alex Hart
3f2b4d60fd Fix voice note saves on API 28 and lower. 2020-12-09 10:22:31 -04:00
Greyson Parrelli
ca633b13af Bump version to 5.0.2 2020-12-08 18:23:07 -05:00
Greyson Parrelli
a671e152bd Updated language translations. 2020-12-08 18:22:44 -05:00
Cody Henthorne
a564aae80a Do not show speaker hint in pip. 2020-12-08 18:10:04 -05:00
Greyson Parrelli
9f8e31db78 Change WebsocketDrainedConstraint to DecryptionsDrainedConstraint. 2020-12-08 18:10:04 -05:00
Cody Henthorne
84e9282f87 Attempt to reduce number of peek jobs run after being offline. 2020-12-08 18:10:04 -05:00
Alan Evans
3949f4fd45 Hide join group call for inactive groups. 2020-12-08 18:10:04 -05:00
Greyson Parrelli
944a180b68 Ensure GV1->GV2 migrations work via group links. 2020-12-08 18:10:04 -05:00
Greyson Parrelli
9cd1a12b6a Fix NPE in FastJobStorage#getJobCountForQueue(). 2020-12-08 18:10:04 -05:00
Greyson Parrelli
a4a2d2fc0d Log out exception when a backup fails. 2020-12-08 18:10:04 -05:00
Artem Varaksa
6df839612d Fix "Advanced PIN settings" pushing wrong fragment. 2020-12-08 18:10:04 -05:00
Greyson Parrelli
dd630abd0e Fix issue where scrolling could get stuck.
The number of off-screen pages was too small, resulting in the
possibility of you still being offscreen after the pages loaded,
which could lead to loading more data, which could lead to you still
being offscreen, ad infinitum.

Simply increasing the number of buffer
pages resolves it.

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

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

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

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

Thanks to @ali-khannakhjavani

Co-authored-by: ali-khannakhjavani
2020-11-30 18:59:42 -05:00
Jonah Beckford
dda51bf367 Complete update of reproducible build instructions 2020-11-30 18:14:35 -05:00
Greyson Parrelli
a324288d97 Bump version to 4.79.0 2020-11-30 15:32:27 -05:00
Greyson Parrelli
f21d2a2187 Updated language translations. 2020-11-30 15:31:56 -05:00
Cody Henthorne
5272fec948 Change group calling feature flag to boolean. 2020-11-30 15:13:56 -05:00
Alan Evans
fe11ebce55 Inline Group Invite Link feature flags. 2020-11-30 14:50:11 -04:00
Alan Evans
221cf56ddc Enqueue cached layout inflation on background thread. 2020-11-30 13:21:20 -04:00
Greyson Parrelli
7efd8be238 Inline max envelope size feature flag. 2020-11-30 11:47:54 -05:00
Greyson Parrelli
105862b524 Chunk read sync messages.
Same thing we do with read receipts we send to other people. Just missed
this part.
2020-11-30 11:36:04 -05:00
Alan Evans
cce8cdc7bf fixup! Clean up any invalid group V1 ids in database. 2020-11-30 12:32:01 -04:00
Cody Henthorne
834c2c2495 Bump RingRTC to 2.8.4 2020-11-30 11:02:54 -05:00
Greyson Parrelli
59f7ee6682 Remove aspectj for now. 2020-11-27 20:08:10 -05:00
Alan Evans
6cbd68fe9f Clean up any invalid group V1 ids in database. 2020-11-25 15:53:58 -04:00
Alex Hart
e1bf23251f Add support for Android 11 Conversation Bubbles. 2020-11-25 14:11:17 -04:00
Alan Evans
3aebadd90d Use protobuf's reserved keyword. 2020-11-25 13:58:06 -04:00
Alex Hart
e57a35ab3e Localize Conversation Intent creation. 2020-11-25 11:40:05 -04:00
Jack Lloyd
13c014215d Move to Signal Protocol written in Rust.
Co-authored-by: Alex Hart <alex@signal.org>
2020-11-25 11:40:05 -04:00
Alex Hart
02931f1826 Clear voice note media queues within synchronized block. 2020-11-25 11:40:05 -04:00
Cody Henthorne
a640d9e298 Improve group update copy and implement speaker indexing. 2020-11-25 11:40:05 -04:00
Alan Evans
ce68da1613 Reserve service field 20. 2020-11-25 11:40:05 -04:00
Greyson Parrelli
3599122ca6 Delete unnecessary artwork directory. 2020-11-25 11:40:05 -04:00
Greyson Parrelli
0003830a42 Cycle the GV1->GV2 auto migration flag. 2020-11-25 11:40:05 -04:00
Greyson Parrelli
3804a89619 Improve handling of membership changes during a GV1->GV2 migration. 2020-11-25 11:40:05 -04:00
Alex Hart
d4748efd42 Don't show members button if there are no remote people. 2020-11-25 11:40:05 -04:00
Alan Evans
0bda1d46a2 Allow setting local group names and avatars for MMS groups. 2020-11-25 11:40:05 -04:00
Greyson Parrelli
43e3ef2bee Refactor Message Request logic to fix some GV1->GV2 bugs. 2020-11-25 11:40:05 -04:00
Alex Hart
ce44e3949c Add new VIEWED item in RecieptMessage enumeration.
Also includes necessary Database changes for supporting this as well as View-Once receipt support.
2020-11-25 11:37:13 -04:00
Greyson Parrelli
7bb1262571 Upload trace file as separate debuglogs item. 2020-11-25 11:37:13 -04:00
Alex Hart
39f1aea8e3 Bump version to 4.78.5 2020-11-24 14:05:57 -04:00
Alex Hart
bda19d01ed Updated language translations. 2020-11-24 13:39:59 -04:00
Alex Hart
1f5364f01d Do not crash if RECIPIENT_EXTRA is null. 2020-11-24 13:22:41 -04:00
Alex Hart
65e88d2d1c Bump version to 4.78.4 2020-11-23 10:48:48 -04:00
Alex Hart
cef8aa67dd Updated language translations. 2020-11-23 10:43:51 -04:00
Alex Hart
5941b22eb6 Revert "Move to Signal Protocol written in Rust."
This reverts commit 907e8d93a3.
2020-11-23 10:22:53 -04:00
Alex Hart
9e7c55847e Bump version to 4.78.3 2020-11-20 16:54:53 -04:00
Alex Hart
5209b74605 Updated language translations. 2020-11-20 16:51:57 -04:00
Cody Henthorne
b90a74d26a Add additional Group Calling features. 2020-11-20 15:42:46 -05:00
Alan Evans
8c1737e597 Increase uncompressed video attachment size to 300 Mb. 2020-11-20 15:15:42 -04:00
Greyson Parrelli
2ea5bd2d44 Convert GV1->GV2 migration flags to booleans. 2020-11-20 13:50:14 -05:00
Greyson Parrelli
4166e7931e Fix membership diffs that occur during a GV1->GV2 migration.
Co-authored-by: Alan Evans <alan@signal.org>
2020-11-20 13:26:17 -05:00
Alan Evans
89f2c25d73 Display video file output size and duration during clipping.
Prevent video upscale, i.e. use input bit rate if lower than our normal target rates.
Do not time limit videos that are under the send file size.
Increase time limit to 10 minutes to match our lowest acceptable bitrate.
2020-11-20 13:27:58 -04:00
Alan Evans
abb1ca2afe Increase in-app recording duration to 60 seconds. 2020-11-20 13:11:48 -04:00
Greyson Parrelli
f7befd1593 Block GV1 creation if forced migrations are enabled. 2020-11-20 11:49:18 -05:00
Greyson Parrelli
28511de23c Ensure we properly detect update messages for migrations. 2020-11-20 11:39:55 -05:00
Greyson Parrelli
2ff3d1b7c5 Update phrasing on donate megaphone dismiss button. 2020-11-19 13:46:35 -05:00
Greyson Parrelli
fe6ae7e142 Don't show donate or research megaphones on new app installs. 2020-11-19 08:42:35 -05:00
Greyson Parrelli
0da6c83ce4 Bump version to 4.78.2 2020-11-18 19:52:48 -05:00
Greyson Parrelli
184b7db43c Updated language translations. 2020-11-18 19:51:15 -05:00
Greyson Parrelli
e442e34c1b More reliably setup initial preferences. 2020-11-18 19:47:27 -05:00
Greyson Parrelli
011efb0ce7 Request READ_PHONE_NUMBERS permission when necessary. 2020-11-18 19:47:27 -05:00
Alex Hart
63d00f87d8 Bump version to 4.78.1 2020-11-18 19:26:12 -04:00
Alex Hart
0323858145 Updated language translations. 2020-11-18 19:22:19 -04:00
Greyson Parrelli
a70e8ec7a7 Update reproducible build instructions. 2020-11-18 19:11:48 -04:00
Alex Hart
b306a3ef41 Update Dockerfile to utilize new commandline tools distributable. 2020-11-18 19:11:48 -04:00
Greyson Parrelli
ccd3467a61 Fix crash with MediaSendActivity progress dialog.
Co-authored-by: Alan Evans <alan@signal.org>
2020-11-18 17:31:43 -05:00
Alex Hart
40338afe7a Bump version to 4.78.0 2020-11-18 16:30:43 -04:00
Alex Hart
ff97f6af56 Updated language translations. 2020-11-18 16:30:43 -04:00
Alan Evans
6e7858e00f Restrict video send duration. 2020-11-18 16:30:43 -04:00
Greyson Parrelli
95468c85a8 Break large read receipt messages into chunks. 2020-11-18 14:19:28 -05:00
Cody Henthorne
f59e10d82c Fix read/unread conversation list colors. 2020-11-18 14:00:14 -05:00
Alex Hart
930370783e Implement ShortcutInfo for API 30. 2020-11-18 14:25:01 -04:00
Alex Hart
75062ada8a Upgrade SDK to 30. 2020-11-18 13:38:27 -04:00
Cody Henthorne
23618923d8 Attempt to recover from reoccurring exceptions when showing notifications. 2020-11-18 12:28:05 -05:00
Greyson Parrelli
f1d3a2f322 Fix Android 11 issue where keyboard wasn't auto-showing for PIN reminders. 2020-11-18 11:57:33 -05:00
Cody Henthorne
3b7fbbaf6e Fix crash when call concluded on non-existent remote peer. 2020-11-18 11:34:06 -05:00
Greyson Parrelli
725d793b20 Fix issue with link preview UI sizing. 2020-11-18 11:33:44 -05:00
Greyson Parrelli
5c3baca055 Add support for a donation megaphone. 2020-11-18 10:33:46 -05:00
Alan Evans
6e5abc92a0 Fix situation where group thread does not yet exist. 2020-11-17 15:52:38 -04:00
Alex Hart
8df6e95781 Stop proximity sensor on pause. 2020-11-17 15:15:13 -04:00
Alex Hart
2290a6c0df Synchronize voice note queue reads and writes. 2020-11-17 14:42:01 -04:00
Jack Lloyd
907e8d93a3 Move to Signal Protocol written in Rust.
Co-authored-by: Alex Hart <alex@signal.org>
2020-11-16 12:28:11 -05:00
Cody Henthorne
918497fb94 Bump version to 4.77.3 2020-11-16 11:49:35 -05:00
Cody Henthorne
3ccd6304c7 Updated language translations. 2020-11-16 11:47:55 -05:00
Greyson Parrelli
51d47adf57 Fix issue where FeatureFlags were triggering listeners for non-changes. 2020-11-16 11:27:58 -05:00
Cody Henthorne
f1e5206f56 Fix Invite Friend theming bug. 2020-11-16 10:17:42 -05:00
Cody Henthorne
f410635e2c Bump version to 4.77.2 2020-11-13 15:01:12 -05:00
Cody Henthorne
302d57bf19 Updated language translations. 2020-11-13 14:54:53 -05:00
Fumiaki Yoshimatsu
4c301a49b4 Fix appearance of small audio view to show correct background color and the progress circle. 2020-11-13 14:39:46 -05:00
Cody Henthorne
4ecfee292e Fix incorrect restarting and theming when system changes night mode. 2020-11-13 14:39:00 -05:00
Alex Hart
2a193ef455 Refactor with WindowUtil and correct some colors. 2020-11-13 14:43:58 -04:00
Cody Henthorne
96e241ef9c Fix RTL constraints for Help screen. 2020-11-13 12:32:55 -05:00
Cody Henthorne
e294a895e8 Bump version to 4.77.1 2020-11-12 12:54:33 -05:00
Cody Henthorne
003b9b1551 Updated language translations. 2020-11-12 12:49:45 -05:00
Alex Hart
a4e4af502e Retheme action modes. 2020-11-12 13:42:07 -04:00
Alex Hart
06aada20c1 Open keyboard when we open contact selection from blocked preference. 2020-11-12 13:39:38 -04:00
Greyson Parrelli
2dace38d43 Add support for GV1->GV2 forced migration. 2020-11-12 12:32:10 -05:00
Greyson Parrelli
554aa1ddf0 Trim message bodies at display time. 2020-11-12 12:18:20 -05:00
Greyson Parrelli
3b2a5f1ce3 Remove old profile sharing UI. 2020-11-12 12:01:43 -05:00
Cody Henthorne
3fc4b098e8 Show correct emojis for recipient names. 2020-11-12 11:22:00 -05:00
Fumiaki Yoshimatsu
a7d672f6b4 Apply locale updates correctly for appcompat-v1.2.0.
Fixes #9736

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

Co-authored-by: Cody Henthorne <cody@signal.org>
2020-11-12 09:56:07 -05:00
Greyson Parrelli
7e347f5cce Add support for manual initiation of GV1->GV2 migrations. 2020-11-12 09:52:21 -05:00
Cody Henthorne
4eaa6ebb47 Bump version to 4.77.0 2020-11-11 15:39:00 -05:00
Cody Henthorne
e85ef6881d Updated language translations. 2020-11-11 15:34:15 -05:00
Cody Henthorne
b1f6786392 Add initial support for Group Calling. 2020-11-11 15:29:02 -05:00
Cody Henthorne
696fffb603 Improve mention notifications by only showing alerting notifications once. 2020-11-11 15:29:02 -05:00
Alan Evans
3bb366ee04 Do not send typing indicator when deleting from the end & send stopped typing indicator when compose completely empty. 2020-11-11 15:29:02 -05:00
Alex Hart
6a59974f89 Add group settings UI polish. 2020-11-11 15:29:02 -05:00
Alan Evans
8e39267c42 Center number display vertically for non-signal contacts. 2020-11-11 15:29:02 -05:00
Jim Gustafson
b937534ce5 Update to RingRTC v2.8.0. 2020-11-11 15:29:01 -05:00
Alex Hart
f5b46f7356 Consolidate AnimatedDialog themes to single DayNight theme. 2020-11-11 15:29:01 -05:00
Greyson Parrelli
cd58c09be3 Proper handling of GV1->GV2 migrations in storage service. 2020-11-11 15:29:01 -05:00
Greyson Parrelli
e8f0038c36 Perform bulk receipt processing in a transaction. 2020-11-11 15:29:01 -05:00
Greyson Parrelli
0b77b33902 Add the ability to trace methods in internal builds.
Currently only for internal builds. Use the @Trace annotation to trace
methods for viewing in Perfetto.
2020-11-11 15:29:01 -05:00
Cody Henthorne
c3b5323010 Update assets and themes to leverage DayNight system. 2020-11-11 15:29:01 -05:00
Greyson Parrelli
81eaae4070 Update emoji to Unicode 13.0 2020-11-11 15:29:01 -05:00
Cody Henthorne
65461ce86f Fix incorrect reaction notification copy for various attachment types.
Fixes #10141. Thanks to @Sgn-32 for the initial PR.
2020-11-11 15:29:01 -05:00
Cody Henthorne
536e3139a2 Add foundation for using Android's DayNight theming system. 2020-11-11 15:29:01 -05:00
Alex Hart
e9c7b120a0 Improve contact blocking UX via settings. 2020-11-11 15:29:01 -05:00
Cody Henthorne
d6a230a235 Update AppCompat to 1.2 along with other Android UI libraries. 2020-11-11 15:29:01 -05:00
Alex Hart
6bf300ada8 Do not require write to read from single backup uri. 2020-11-11 15:29:01 -05:00
Greyson Parrelli
d307db8a95 Add the ability to add suggested members after a GV1 migration. 2020-11-11 15:29:01 -05:00
Alex Hart
c4c32d80b2 Update CameraX to 1.0.0-beta11. 2020-11-11 15:29:01 -05:00
Greyson Parrelli
f4c1e34402 Enforce max envelope size in more places. 2020-11-11 15:29:00 -05:00
Alan Evans
0068d62122 Bump version to 4.76.3 2020-11-09 14:39:30 -04:00
Alan Evans
3f1fa59e09 Updated language translations. 2020-11-09 14:38:11 -04:00
Greyson Parrelli
df5114c62c Fix website signing task. 2020-11-09 14:21:56 -04:00
Greyson Parrelli
956e3924ff Log the version in our PersistentLogger. 2020-11-09 12:47:10 -05:00
Greyson Parrelli
20ad166e0f Fix issue where we were double-logging job info. 2020-11-09 12:18:45 -05:00
Greyson Parrelli
12ea88f409 Improve logging around deletions. 2020-11-09 12:18:27 -05:00
Alan Evans
0c5648bfb1 Hide "Read More" when long message is remote deleted. 2020-11-09 10:24:11 -04:00
1951 changed files with 29836 additions and 13686 deletions

View File

@@ -22,7 +22,7 @@ jobs:
java-version: 1.8
- name: Install NDK
run: echo "y" | sudo /usr/local/lib/android/sdk/tools/bin/sdkmanager --install "ndk;20.0.5594570" --sdk_root=${ANDROID_SDK_ROOT}
run: echo "y" | sudo /usr/local/lib/android/sdk/tools/bin/sdkmanager --install "ndk;21.0.6113669" --sdk_root=${ANDROID_SDK_ROOT}
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1

View File

@@ -2,25 +2,6 @@ import org.signal.signing.ApkSignerUtil
import java.security.MessageDigest
buildscript {
repositories {
google()
maven {
url "https://repo1.maven.org/maven2"
}
jcenter {
content {
includeVersion 'org.jetbrains.trove4j', 'trove4j', '20160824'
}
}
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath 'androidx.navigation:navigation-safe-args-gradle-plugin:2.1.0'
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.10'
}
}
apply plugin: 'com.android.application'
apply plugin: 'com.google.protobuf'
apply plugin: 'androidx.navigation.safeargs'
@@ -80,8 +61,8 @@ protobuf {
}
}
def canonicalVersionCode = 735
def canonicalVersionName = "4.76.2"
def canonicalVersionCode = 755
def canonicalVersionName = "5.0.4"
def postFixSize = 10
def abiPostFix = ['universal' : 0,
@@ -93,9 +74,10 @@ def abiPostFix = ['universal' : 0,
def keystores = [ 'debug' : loadKeystoreProperties('keystore.debug.properties') ]
android {
buildToolsVersion BUILD_TOOL_VERSION
compileSdkVersion COMPILE_SDK
flavorDimensions 'distribution', 'environment'
compileSdkVersion 29
buildToolsVersion '29.0.3'
useLibrary 'org.apache.http.legacy'
dexOptions {
@@ -117,8 +99,9 @@ android {
versionCode canonicalVersionCode * postFixSize
versionName canonicalVersionName
minSdkVersion 19
targetSdkVersion 29
minSdkVersion MINIMUM_SDK
targetSdkVersion TARGET_SDK
multiDexEnabled true
vectorDrawables.useSupportLibrary = true
@@ -132,6 +115,7 @@ android {
buildConfigField "String", "SIGNAL_CONTACT_DISCOVERY_URL", "\"https://api.directory.signal.org\""
buildConfigField "String", "SIGNAL_SERVICE_STATUS_URL", "\"uptime.signal.org\""
buildConfigField "String", "SIGNAL_KEY_BACKUP_URL", "\"https://api.backup.signal.org\""
buildConfigField "String", "SIGNAL_SFU_URL", "\"https://sfu.voip.signal.org\""
buildConfigField "String", "CONTENT_PROXY_HOST", "\"contentproxy.signal.org\""
buildConfigField "int", "CONTENT_PROXY_PORT", "443"
buildConfigField "String", "SIGNAL_AGENT", "\"OWA\""
@@ -144,6 +128,7 @@ android {
buildConfigField "String", "ZKGROUP_SERVER_PUBLIC_PARAMS", "\"AMhf5ywVwITZMsff/eCyudZx9JDmkkkbV6PInzG4p8x3VqVJSFiMvnvlEKWuRob/1eaIetR31IYeAbm0NdOuHH8Qi+Rexi1wLlpzIo1gstHWBfZzy1+qHRV5A4TqPp15YzBPm0WSggW6PbSn+F4lf57VCnHF7p8SvzAA2ZZJPYJURt8X7bbg+H3i+PEjH9DXItNEqs2sNcug37xZQDLm7X0=\""
buildConfigField "String[]", "LANGUAGES", "new String[]{\"" + autoResConfig().collect { s -> s.replace('-r', '_') }.join('", "') + '"}'
buildConfigField "int", "CANONICAL_VERSION_CODE", "$canonicalVersionCode"
buildConfigField "int", "TRACE_EVENT_MAX", "3500"
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
@@ -164,8 +149,8 @@ android {
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JAVA_VERSION
targetCompatibility JAVA_VERSION
}
packagingOptions {
@@ -215,6 +200,7 @@ android {
initWith debug
isDefault false
minifyEnabled false
matchingFallbacks = ['debug']
}
release {
minifyEnabled true
@@ -243,6 +229,7 @@ android {
ext.websiteUpdateUrl = "null"
buildConfigField "boolean", "PLAY_STORE_DISABLED", "false"
buildConfigField "String", "NOPLAY_UPDATE_URL", "$ext.websiteUpdateUrl"
buildConfigField "int", "TRACE_EVENT_MAX", "30_000"
}
prod {
@@ -300,27 +287,28 @@ android {
dependencies {
lintChecks project(':lintchecks')
implementation('androidx.appcompat:appcompat:1.1.0-beta01') {
implementation ('androidx.appcompat:appcompat:1.2.0') {
force = true
}
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'com.google.android.material:material:1.1.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.legacy:legacy-support-v13:1.0.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.preference:preference:1.0.0'
implementation 'androidx.legacy:legacy-preference-v14:1.0.0'
implementation 'androidx.gridlayout:gridlayout:1.0.0'
implementation 'androidx.exifinterface:exifinterface:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.navigation:navigation-fragment:2.1.0'
implementation 'androidx.navigation:navigation-ui:2.1.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:1.0.0-alpha05'
implementation 'androidx.lifecycle:lifecycle-common-java8:2.1.0'
implementation "androidx.camera:camera-core:1.0.0-beta01"
implementation "androidx.camera:camera-camera2:1.0.0-beta01"
implementation "androidx.camera:camera-lifecycle:1.0.0-beta01"
implementation "androidx.camera:camera-core:1.0.0-beta11"
implementation "androidx.camera:camera-camera2:1.0.0-beta11"
implementation "androidx.camera:camera-lifecycle:1.0.0-beta11"
implementation "androidx.camera:camera-view:1.0.0-alpha18"
implementation "androidx.concurrent:concurrent-futures:1.0.0"
implementation "androidx.autofill:autofill:1.0.0"
implementation "androidx.paging:paging-common:2.1.2"
@@ -345,11 +333,14 @@ dependencies {
implementation 'org.signal:aesgcmprovider:0.0.3'
implementation project(':libsignal-service')
implementation project(':paging')
implementation project(':core-util')
implementation 'org.signal:zkgroup-android:0.7.0'
implementation 'org.whispersystems:signal-client-android:0.1.5'
implementation 'com.google.protobuf:protobuf-javalite:3.10.0'
implementation 'org.signal:argon2:13.1@aar'
implementation 'org.signal:ringrtc-android:2.7.3'
implementation 'org.signal:ringrtc-android:2.8.7'
implementation "me.leolin:ShortcutBadger:1.1.16"
implementation 'se.emilsjolander:stickylistheaders:2.7.0'
@@ -424,7 +415,6 @@ dependencyVerification {
configuration = '(play|website)(Prod|Staging)(Debug|Release)RuntimeClasspath'
}
def assembleWebsiteDescriptor = { variant, file ->
if (file.exists()) {
MessageDigest md = MessageDigest.getInstance("SHA-256");
@@ -480,7 +470,7 @@ task signProductionInternalRelease {
task signProductionWebsiteRelease {
doLast {
def variant = android.applicationVariants.find { (it.name == 'websiteRelease') }
def variant = android.applicationVariants.find { (it.name == 'websiteProdRelease') }
File signedRelease = signProductionRelease(variant).find { it.name.contains('universal') }
assembleWebsiteDescriptor(variant, signedRelease)
}

View File

@@ -14,8 +14,8 @@ import net.sqlcipher.DatabaseUtils;
import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteStatement;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.logging.Log;
import java.lang.reflect.Field;
import java.util.ArrayList;
@@ -247,11 +247,11 @@ public class FlipperSqlCipherAdapter extends DatabaseDriver<FlipperSqlCipherAdap
}
public @NonNull SQLiteDatabase getReadable() {
return sqlCipherOpenHelper.getReadableDatabase();
return sqlCipherOpenHelper.getReadableDatabase().getSqlCipherDatabase();
}
public @NonNull SQLiteDatabase getWritable() {
return sqlCipherOpenHelper.getWritableDatabase();
return sqlCipherOpenHelper.getWritableDatabase().getSqlCipherDatabase();
}
}
}

View File

@@ -3,7 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
package="org.thoughtcrime.securesms">
<uses-sdk tools:overrideLibrary="androidx.camera.core,androidx.camera.camera2,androidx.camera.lifecycle" />
<uses-sdk tools:overrideLibrary="androidx.camera.core,androidx.camera.camera2,androidx.camera.lifecycle,androidx.camera.view" />
<permission android:name="${applicationId}.ACCESS_SECRETS"
android:label="Access to TextSecure Secrets"
@@ -35,6 +35,7 @@
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.WRITE_SMS"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
@@ -115,7 +116,7 @@
<meta-data android:name="firebase_messaging_auto_init_enabled" android:value="false" />
<activity android:name=".WebRtcCallActivity"
android:theme="@style/TextSecure.LightTheme.WebRTCCall"
android:theme="@style/TextSecure.DarkTheme.WebRTCCall"
android:excludeFromRecents="true"
android:screenOrientation="portrait"
android:supportsPictureInPicture="true"
@@ -258,6 +259,11 @@
android:value="org.thoughtcrime.securesms.MainActivity" />
</activity>
<activity android:name=".conversation.BubbleConversationActivity"
android:theme="@style/Signal.DayNight"
android:allowEmbedded="true"
android:resizeableActivity="true" />
<activity android:name=".longmessage.LongMessageActivity" />
<activity android:name=".conversation.ConversationPopupActivity"
@@ -269,15 +275,10 @@
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" />
<activity android:name=".messagedetails.MessageDetailsActivity"
android:label="@string/AndroidManifest__message_details"
android:windowSoftInputMode="stateHidden"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".groups.ui.pendingmemberinvites.PendingMemberInvitesActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:theme="@style/Theme.Signal.DayNight.NoActionBar" />
<activity android:name=".groups.ui.invitesandrequests.ManagePendingAndRequestingMembersActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"
android:theme="@style/Theme.Signal.DayNight.NoActionBar" />
@@ -372,7 +373,6 @@
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".logsubmit.SubmitDebugLogActivity"
android:label="@string/AndroidManifest__log_submit"
android:windowSoftInputMode="stateHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
@@ -443,7 +443,7 @@
android:theme="@style/TextSecure.FullScreenMedia"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".BlockedContactsActivity"
<activity android:name=".blocked.BlockedUsersActivity"
android:theme="@style/TextSecure.LightTheme"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
@@ -465,17 +465,11 @@
android:windowSoftInputMode="adjustResize"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".ClearProfileAvatarActivity"
android:theme="@style/Theme.AppCompat.Dialog.Alert"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:icon="@drawable/clear_profile_avatar"
android:label="@string/AndroidManifest_remove_photo">
<intent-filter>
<action android:name="org.thoughtcrime.securesms.action.CLEAR_PROFILE_PHOTO"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name=".ClearAvatarPromptActivity"
android:theme="@style/Theme.AppCompat.Dialog.Alert"
android:icon="@drawable/clear_profile_avatar"
android:label="@string/AndroidManifest_remove_photo"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".contacts.TurnOffContactJoinedNotificationsActivity"
android:theme="@style/Theme.AppCompat.Dialog.Alert" />
@@ -802,12 +796,5 @@
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
<uses-library android:name="com.sec.android.app.multiwindow" android:required="false"/>
<meta-data android:name="com.sec.android.support.multiwindow" android:value="true" />
<meta-data android:name="com.sec.android.multiwindow.DEFAULT_SIZE_W" android:value="632.0dip" />
<meta-data android:name="com.sec.android.multiwindow.DEFAULT_SIZE_H" android:value="598.0dip" />
<meta-data android:name="com.sec.android.multiwindow.MINIMUM_SIZE_W" android:value="632.0dip" />
<meta-data android:name="com.sec.android.multiwindow.MINIMUM_SIZE_H" android:value="598.0dip" />
</application>
</manifest>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 225 KiB

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 415 KiB

After

Width:  |  Height:  |  Size: 421 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 KiB

After

Width:  |  Height:  |  Size: 365 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 395 KiB

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 622 KiB

After

Width:  |  Height:  |  Size: 664 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 599 KiB

After

Width:  |  Height:  |  Size: 608 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 559 KiB

After

Width:  |  Height:  |  Size: 552 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 643 KiB

After

Width:  |  Height:  |  Size: 631 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 647 KiB

After

Width:  |  Height:  |  Size: 653 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 602 KiB

After

Width:  |  Height:  |  Size: 652 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 589 KiB

After

Width:  |  Height:  |  Size: 531 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 531 KiB

After

Width:  |  Height:  |  Size: 685 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 589 KiB

After

Width:  |  Height:  |  Size: 603 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 384 KiB

After

Width:  |  Height:  |  Size: 391 KiB

View File

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

View File

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

View File

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

View File

@@ -4,12 +4,12 @@ import android.content.Context;
import androidx.annotation.NonNull;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.insights.InsightsOptOut;
import org.thoughtcrime.securesms.jobmanager.JobManager;
import org.thoughtcrime.securesms.jobs.StickerPackDownloadJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.migrations.ApplicationMigrations;
import org.thoughtcrime.securesms.stickers.BlessedPacks;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
@@ -34,6 +34,11 @@ public final class AppInitialization {
TextSecurePreferences.setJobManagerVersion(context, JobManager.CURRENT_VERSION);
TextSecurePreferences.setLastExperienceVersionCode(context, Util.getCanonicalVersionCode());
TextSecurePreferences.setHasSeenStickerIntroTooltip(context, true);
TextSecurePreferences.setPasswordDisabled(context, true);
TextSecurePreferences.setLastExperienceVersionCode(context, Util.getCanonicalVersionCode());
TextSecurePreferences.setReadReceiptsEnabled(context, true);
TextSecurePreferences.setTypingIndicatorsEnabled(context, true);
TextSecurePreferences.setHasSeenWelcomeScreen(context, false);
ApplicationDependencies.getMegaphoneRepository().onFirstEverAppLaunch();
SignalStore.onFirstEverAppLaunch();
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forInstall(BlessedPacks.ZOZO.getPackId(), BlessedPacks.ZOZO.getPackKey(), false));

View File

@@ -33,10 +33,12 @@ import com.google.android.gms.security.ProviderInstaller;
import org.conscrypt.Conscrypt;
import org.signal.aesgcmprovider.AesGcmProvider;
import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.AndroidLogger;
import org.signal.core.util.logging.Log;
import org.signal.core.util.logging.PersistentLogger;
import org.signal.glide.SignalGlideCodecs;
import org.signal.ringrtc.CallManager;
import org.thoughtcrime.securesms.components.TypingStatusRepository;
import org.thoughtcrime.securesms.components.TypingStatusSender;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
@@ -50,11 +52,8 @@ import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
import org.thoughtcrime.securesms.jobs.RefreshPreKeysJob;
import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.logging.AndroidLogger;
import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.logging.PersistentLogger;
import org.thoughtcrime.securesms.logging.SignalUncaughtExceptionHandler;
import org.thoughtcrime.securesms.logging.LogSecretProvider;
import org.thoughtcrime.securesms.migrations.ApplicationMigrations;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.providers.BlobProvider;
@@ -70,10 +69,13 @@ import org.thoughtcrime.securesms.service.RotateSenderCertificateListener;
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
import org.thoughtcrime.securesms.service.UpdateApkRefreshListener;
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
import org.thoughtcrime.securesms.tracing.Trace;
import org.thoughtcrime.securesms.tracing.Tracer;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.SignalUncaughtExceptionHandler;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageContextWrapper;
import org.webrtc.voiceengine.WebRtcAudioManager;
import org.webrtc.voiceengine.WebRtcAudioUtils;
@@ -92,15 +94,14 @@ import java.util.concurrent.TimeUnit;
*
* @author Moxie Marlinspike
*/
@Trace
public class ApplicationContext extends MultiDexApplication implements DefaultLifecycleObserver {
private static final String TAG = ApplicationContext.class.getSimpleName();
private ExpiringMessageManager expiringMessageManager;
private ViewOnceMessageManager viewOnceMessageManager;
private TypingStatusRepository typingStatusRepository;
private TypingStatusSender typingStatusSender;
private PersistentLogger persistentLogger;
private ExpiringMessageManager expiringMessageManager;
private ViewOnceMessageManager viewOnceMessageManager;
private PersistentLogger persistentLogger;
private volatile boolean isAppVisible;
@@ -110,8 +111,11 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
@Override
public void onCreate() {
Tracer.getInstance().start("Application#onCreate()");
long startTime = System.currentTimeMillis();
super.onCreate();
initializeSecurityProvider();
initializeLogging();
Log.i(TAG, "onCreate()");
@@ -122,8 +126,6 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
initializeMessageRetrieval();
initializeExpiringMessageManager();
initializeRevealableMessageManager();
initializeTypingStatusRepository();
initializeTypingStatusSender();
initializeGcmCheck();
initializeSignedPreKeyCheck();
initializePeriodicTasks();
@@ -146,7 +148,11 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
}
ApplicationDependencies.getJobManager().beginJobLoop();
DynamicTheme.setDefaultDayNightMode(this);
Log.d(TAG, "onCreate() took " + (System.currentTimeMillis() - startTime) + " ms");
Tracer.getInstance().end("Application#onCreate()");
}
@Override
@@ -181,14 +187,6 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
return viewOnceMessageManager;
}
public TypingStatusRepository getTypingStatusRepository() {
return typingStatusRepository;
}
public TypingStatusSender getTypingStatusSender() {
return typingStatusSender;
}
public boolean isAppVisible() {
return isAppVisible;
}
@@ -229,8 +227,8 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
}
private void initializeLogging() {
persistentLogger = new PersistentLogger(this);
org.thoughtcrime.securesms.logging.Log.initialize(new AndroidLogger(), persistentLogger);
persistentLogger = new PersistentLogger(this, LogSecretProvider.getOrCreateAttachmentSecret(this), BuildConfig.VERSION_NAME);
org.signal.core.util.logging.Log.initialize(new AndroidLogger(), persistentLogger);
SignalProtocolLoggerProvider.setProvider(new CustomSignalProtocolLogger());
}
@@ -288,14 +286,6 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
this.viewOnceMessageManager = new ViewOnceMessageManager(this);
}
private void initializeTypingStatusRepository() {
this.typingStatusRepository = new TypingStatusRepository();
}
private void initializeTypingStatusSender() {
this.typingStatusSender = new TypingStatusSender(this);
}
private void initializePeriodicTasks() {
RotateSignedPreKeyListener.schedule(this);
DirectoryRefreshListener.schedule(this);
@@ -424,7 +414,8 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(DynamicLanguageContextWrapper.updateContext(base, TextSecurePreferences.getLanguage(base)));
DynamicLanguageContextWrapper.updateContext(base);
super.attachBaseContext(base);
}
private static class ProviderInitializationException extends RuntimeException {

View File

@@ -18,7 +18,6 @@
package org.thoughtcrime.securesms;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.PorterDuff;
@@ -27,9 +26,9 @@ import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.preference.Preference;
import org.thoughtcrime.securesms.help.HelpFragment;
@@ -48,12 +47,12 @@ import org.thoughtcrime.securesms.preferences.widgets.UsernamePreference;
import org.thoughtcrime.securesms.profiles.edit.EditProfileActivity;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.util.CachedInflater;
import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ThemeUtil;
/**
* The Activity for application preference display and management.
@@ -83,9 +82,13 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
private static final String PREFERENCE_CATEGORY_ADVANCED = "preference_category_advanced";
private static final String PREFERENCE_CATEGORY_DONATE = "preference_category_donate";
private static final String WAS_CONFIGURATION_UPDATED = "was_configuration_updated";
private final DynamicTheme dynamicTheme = new DynamicTheme();
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
private boolean wasConfigurationUpdated = false;
@Override
protected void onPreCreate() {
dynamicTheme.onCreate(this);
@@ -103,9 +106,17 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
initFragment(android.R.id.content, new BackupsPreferenceFragment());
} else if (icicle == null) {
initFragment(android.R.id.content, new ApplicationPreferenceFragment());
} else {
wasConfigurationUpdated = icicle.getBoolean(WAS_CONFIGURATION_UPDATED);
}
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
outState.putBoolean(WAS_CONFIGURATION_UPDATED, wasConfigurationUpdated);
super.onSaveInstanceState(outState);
}
@Override
public void onResume() {
super.onResume();
@@ -127,20 +138,29 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
if (fragmentManager.getBackStackEntryCount() > 0) {
fragmentManager.popBackStack();
} else {
// TODO [greyson] Navigation
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
if (wasConfigurationUpdated) {
setResult(MainActivity.RESULT_CONFIG_CHANGED);
} else {
setResult(RESULT_OK);
}
finish();
}
return true;
}
@Override
public void onBackPressed() {
onSupportNavigateUp();
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals(TextSecurePreferences.THEME_PREF)) {
DynamicTheme.setDefaultDayNightMode(this);
recreate();
} else if (key.equals(TextSecurePreferences.LANGUAGE_PREF)) {
CachedInflater.from(this).clear();
wasConfigurationUpdated = true;
recreate();
Intent intent = new Intent(this, KeyCachingService.class);
@@ -195,7 +215,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
if (Build.VERSION.SDK_INT >= 21) return;
Preference preference = this.findPreference(PREFERENCE_CATEGORY_SMS_MMS);
preference.getIcon().setColorFilter(ThemeUtil.getThemedColor(requireContext(), R.attr.icon_tint), PorterDuff.Mode.SRC_IN);
preference.getIcon().setColorFilter(ContextCompat.getColor(requireContext(), R.color.signal_icon_tint_primary), PorterDuff.Mode.SRC_IN);
}
@Override

View File

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

View File

@@ -1,23 +1,22 @@
package org.thoughtcrime.securesms;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.content.res.Configuration;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.core.app.ActivityCompat;
import androidx.core.app.ActivityOptionsCompat;
import androidx.appcompat.app.AppCompatActivity;
import android.view.View;
import android.view.WindowManager;
import org.thoughtcrime.securesms.logging.Log;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.app.ActivityCompat;
import androidx.core.app.ActivityOptionsCompat;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.util.ConfigurationUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageActivityHelper;
import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageContextWrapper;
import java.util.Objects;
@@ -40,7 +39,6 @@ public abstract class BaseActivity extends AppCompatActivity {
protected void onResume() {
super.onResume();
initializeScreenshotSecurity();
DynamicLanguageActivityHelper.recreateIfNotInCorrectLanguage(this, TextSecurePreferences.getLanguage(this));
}
@Override
@@ -75,16 +73,23 @@ public abstract class BaseActivity extends AppCompatActivity {
ActivityCompat.startActivity(this, intent, bundle);
}
@TargetApi(21)
protected void setStatusBarColor(int color) {
if (Build.VERSION.SDK_INT >= 21) {
getWindow().setStatusBarColor(color);
}
@Override
protected void attachBaseContext(@NonNull Context newBase) {
super.attachBaseContext(newBase);
Configuration configuration = new Configuration(newBase.getResources().getConfiguration());
int appCompatNightMode = getDelegate().getLocalNightMode() != AppCompatDelegate.MODE_NIGHT_UNSPECIFIED ? getDelegate().getLocalNightMode()
: AppCompatDelegate.getDefaultNightMode();
configuration.uiMode = (configuration.uiMode & ~Configuration.UI_MODE_NIGHT_MASK) | mapNightModeToConfigurationUiMode(newBase, appCompatNightMode);
applyOverrideConfiguration(configuration);
}
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(DynamicLanguageContextWrapper.updateContext(newBase, TextSecurePreferences.getLanguage(newBase)));
public void applyOverrideConfiguration(@NonNull Configuration overrideConfiguration) {
DynamicLanguageContextWrapper.prepareOverrideConfiguration(this, overrideConfiguration);
super.applyOverrideConfiguration(overrideConfiguration);
}
private void logEvent(@NonNull String event) {
@@ -94,4 +99,13 @@ public abstract class BaseActivity extends AppCompatActivity {
public final @NonNull ActionBar requireSupportActionBar() {
return Objects.requireNonNull(getSupportActionBar());
}
private static int mapNightModeToConfigurationUiMode(@NonNull Context context, @AppCompatDelegate.NightMode int appCompatNightMode) {
if (appCompatNightMode == AppCompatDelegate.MODE_NIGHT_YES) {
return Configuration.UI_MODE_NIGHT_YES;
} else if (appCompatNightMode == AppCompatDelegate.MODE_NIGHT_NO) {
return Configuration.UI_MODE_NIGHT_NO;
}
return ConfigurationUtil.getNightModeConfiguration(context.getApplicationContext());
}
}

View File

@@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.conversation.ConversationMessage;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient;
@@ -59,7 +60,8 @@ public interface BindableConversationItem extends Unbindable {
void onVoiceNotePause(@NonNull Uri uri);
void onVoiceNotePlay(@NonNull Uri uri, long messageId, double position);
void onVoiceNoteSeekTo(@NonNull Uri uri, double position);
void onGroupMigrationLearnMoreClicked(@NonNull List<RecipientId> pendingRecipients);
void onGroupMigrationLearnMoreClicked(@NonNull GroupMigrationMembershipChange membershipChange);
void onJoinGroupCallClicked();
/** @return true if handled, false if you want to let the normal url handling continue */
boolean onUrlClicked(@NonNull String url);

View File

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

View File

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

View File

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

View File

@@ -14,9 +14,7 @@ import androidx.appcompat.app.AlertDialog;
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessageDatabase;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.PushDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;

View File

@@ -22,10 +22,10 @@ import android.os.Bundle;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.components.ContactFilterToolbar;
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;

View File

@@ -55,6 +55,7 @@ import com.annimon.stream.Stream;
import com.google.android.material.chip.ChipGroup;
import com.pnikosis.materialishprogress.ProgressWheel;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.components.RecyclerViewFastScroller;
import org.thoughtcrime.securesms.components.emoji.WarningTextView;
import org.thoughtcrime.securesms.contacts.ContactChip;
@@ -66,7 +67,6 @@ import org.thoughtcrime.securesms.contacts.SelectedContact;
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
import org.thoughtcrime.securesms.groups.SelectionLimits;
import org.thoughtcrime.securesms.groups.ui.GroupLimitDialog;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.permissions.Permissions;

View File

@@ -18,10 +18,10 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.qr.ScanListener;
import org.thoughtcrime.securesms.util.Base64;

View File

@@ -5,8 +5,6 @@ import android.annotation.TargetApi;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewAnimationUtils;
@@ -15,6 +13,8 @@ import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.components.camera.CameraView;
import org.thoughtcrime.securesms.qr.ScanListener;
import org.thoughtcrime.securesms.qr.ScanningThread;

View File

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

View File

@@ -6,15 +6,6 @@ import android.content.Context;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.ListFragment;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader;
import androidx.appcompat.app.AlertDialog;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.devicelist.Device;
import org.thoughtcrime.securesms.logging.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -24,12 +15,21 @@ import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.ListFragment;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader;
import com.melnykov.fab.FloatingActionButton;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.database.loaders.DeviceListLoader;
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.devicelist.Device;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import java.io.IOException;

View File

@@ -2,9 +2,10 @@ package org.thoughtcrime.securesms;
import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AlertDialog;
import android.view.Window;
import androidx.appcompat.app.AlertDialog;
public class DeviceProvisioningActivity extends PassphraseRequiredActivity {
@SuppressWarnings("unused")

View File

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

View File

@@ -164,10 +164,10 @@ public class InviteActivity extends PassphraseRequiredActivity implements Contac
private void setPrimaryColorsToolbarNormal() {
primaryToolbar.setBackgroundColor(0);
primaryToolbar.getNavigationIcon().setColorFilter(null);
primaryToolbar.setTitleTextColor(ThemeUtil.getThemedColor(this, R.attr.title_text_color_primary));
primaryToolbar.setTitleTextColor(ContextCompat.getColor(this, R.color.signal_text_primary));
if (Build.VERSION.SDK_INT >= 23) {
getWindow().setStatusBarColor(ThemeUtil.getThemedColor(this, android.R.attr.statusBarColor));
WindowUtil.setStatusBarColor(getWindow(), ThemeUtil.getThemedColor(this, android.R.attr.statusBarColor));
getWindow().setNavigationBarColor(ThemeUtil.getThemedColor(this, android.R.attr.navigationBarColor));
WindowUtil.setLightStatusBarFromTheme(this);
}
@@ -177,11 +177,11 @@ public class InviteActivity extends PassphraseRequiredActivity implements Contac
private void setPrimaryColorsToolbarForSms() {
primaryToolbar.setBackgroundColor(ContextCompat.getColor(this, R.color.core_ultramarine));
primaryToolbar.getNavigationIcon().setColorFilter(ThemeUtil.getThemedColor(this, R.attr.conversation_subtitle_color), PorterDuff.Mode.SRC_IN);
primaryToolbar.setTitleTextColor(ThemeUtil.getThemedColor(this, R.attr.conversation_title_color));
primaryToolbar.getNavigationIcon().setColorFilter(ContextCompat.getColor(this, R.color.signal_text_toolbar_subtitle), PorterDuff.Mode.SRC_IN);
primaryToolbar.setTitleTextColor(ContextCompat.getColor(this, R.color.signal_text_toolbar_title));
if (Build.VERSION.SDK_INT >= 23) {
getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.core_ultramarine));
WindowUtil.setStatusBarColor(getWindow(), ContextCompat.getColor(this, R.color.core_ultramarine));
WindowUtil.clearLightStatusBar(getWindow());
}

View File

@@ -6,7 +6,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import org.thoughtcrime.securesms.logging.Log;
import org.signal.core.util.logging.Log;
/**
* Simply logs out lifecycle events.

View File

@@ -1,17 +1,24 @@
package org.thoughtcrime.securesms;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.tracing.Trace;
import org.thoughtcrime.securesms.util.CachedInflater;
import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
@Trace
public class MainActivity extends PassphraseRequiredActivity {
public static final int RESULT_CONFIG_CHANGED = Activity.RESULT_FIRST_USER + 901;
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
private final MainNavigator navigator = new MainNavigator(this);
@@ -23,6 +30,8 @@ public class MainActivity extends PassphraseRequiredActivity {
navigator.onCreate(savedInstanceState);
handleGroupLinkInIntent(getIntent());
CachedInflater.from(this).clear();
}
@Override
@@ -50,6 +59,14 @@ public class MainActivity extends PassphraseRequiredActivity {
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == MainNavigator.REQUEST_CONFIG_CHANGES && resultCode == RESULT_CONFIG_CHANGED) {
recreate();
}
}
public @NonNull MainNavigator getNavigator() {
return navigator;
}

View File

@@ -9,7 +9,7 @@ import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import org.thoughtcrime.securesms.conversation.ConversationActivity;
import org.thoughtcrime.securesms.conversation.ConversationIntents;
import org.thoughtcrime.securesms.conversationlist.ConversationListArchiveFragment;
import org.thoughtcrime.securesms.conversationlist.ConversationListFragment;
import org.thoughtcrime.securesms.groups.ui.creategroup.CreateGroupActivity;
@@ -18,6 +18,8 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
public class MainNavigator {
public static final int REQUEST_CONFIG_CHANGES = 901;
private final MainActivity activity;
public MainNavigator(@NonNull MainActivity activity) {
@@ -57,7 +59,10 @@ public class MainNavigator {
}
public void goToConversation(@NonNull RecipientId recipientId, long threadId, int distributionType, int startingPosition) {
Intent intent = ConversationActivity.buildIntent(activity, recipientId, threadId, distributionType, startingPosition);
Intent intent = ConversationIntents.createBuilder(activity, recipientId, threadId)
.withDistributionType(distributionType)
.withStartingPosition(startingPosition)
.build();
activity.startActivity(intent);
activity.overridePendingTransition(R.anim.slide_from_end, R.anim.fade_scale_out);
@@ -65,10 +70,9 @@ public class MainNavigator {
public void goToAppSettings() {
Intent intent = new Intent(activity, ApplicationPreferencesActivity.class);
activity.startActivity(intent);
activity.startActivityForResult(intent, REQUEST_CONFIG_CHANGES);
}
public void goToArchiveList() {
getFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.slide_from_end, R.anim.slide_to_start, R.anim.slide_from_start, R.anim.slide_to_end)

View File

@@ -39,6 +39,7 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.app.ShareCompat;
import androidx.core.util.Pair;
import androidx.core.view.ViewCompat;
@@ -52,13 +53,13 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager.widget.ViewPager;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.animation.DepthPageTransformer;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.components.viewpager.ExtendedOnPageChangedListener;
import org.thoughtcrime.securesms.database.MediaDatabase;
import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
import org.thoughtcrime.securesms.database.loaders.PagingMediaLoader;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mediaoverview.MediaOverviewActivity;
import org.thoughtcrime.securesms.mediapreview.MediaPreviewFragment;
import org.thoughtcrime.securesms.mediapreview.MediaPreviewViewModel;
@@ -142,6 +143,12 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
return intent;
}
@Override
protected void attachBaseContext(@NonNull Context newBase) {
getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES);
super.attachBaseContext(newBase);
}
@SuppressWarnings("ConstantConditions")
@Override
protected void onCreate(Bundle bundle, boolean ready) {
@@ -442,7 +449,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setIconAttribute(R.attr.dialog_alert_icon);
builder.setIcon(R.drawable.ic_warning);
builder.setTitle(R.string.MediaPreviewActivity_media_delete_confirmation_title);
builder.setMessage(R.string.MediaPreviewActivity_media_delete_confirmation_message);
builder.setCancelable(true);

View File

@@ -1,8 +1,8 @@
package org.thoughtcrime.securesms;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;

View File

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

View File

@@ -21,8 +21,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import org.thoughtcrime.securesms.logging.Log;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.service.KeyCachingService;

View File

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

View File

@@ -22,8 +22,6 @@ import android.os.Bundle;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.VersionTracker;
/**
@@ -66,12 +64,6 @@ public class PassphraseCreateActivity extends PassphraseActivity {
IdentityKeyUtil.generateIdentityKeys(PassphraseCreateActivity.this);
VersionTracker.updateLastSeenVersion(PassphraseCreateActivity.this);
TextSecurePreferences.setLastExperienceVersionCode(PassphraseCreateActivity.this, Util.getCanonicalVersionCode());
TextSecurePreferences.setPasswordDisabled(PassphraseCreateActivity.this, true);
TextSecurePreferences.setReadReceiptsEnabled(PassphraseCreateActivity.this, true);
TextSecurePreferences.setTypingIndicatorsEnabled(PassphraseCreateActivity.this, true);
TextSecurePreferences.setHasSeenWelcomeScreen(PassphraseCreateActivity.this, false);
return null;
}

View File

@@ -24,16 +24,12 @@ import android.content.Intent;
import android.graphics.PorterDuff;
import android.os.Build;
import android.os.Bundle;
import androidx.core.hardware.fingerprint.FingerprintManagerCompat;
import androidx.core.os.CancellationSignal;
import androidx.appcompat.widget.Toolbar;
import android.text.Editable;
import android.text.InputType;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.RelativeSizeSpan;
import android.text.style.TypefaceSpan;
import org.thoughtcrime.securesms.logging.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
@@ -50,6 +46,11 @@ import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.widget.Toolbar;
import androidx.core.hardware.fingerprint.FingerprintManagerCompat;
import androidx.core.os.CancellationSignal;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.animation.AnimationCompleteListener;
import org.thoughtcrime.securesms.components.AnimatingToggle;
import org.thoughtcrime.securesms.crypto.InvalidPassphraseException;

View File

@@ -11,12 +11,12 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.migrations.ApplicationMigrationActivity;
import org.thoughtcrime.securesms.migrations.ApplicationMigrations;
import org.thoughtcrime.securesms.pin.PinRestoreActivity;
@@ -25,6 +25,7 @@ import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.registration.RegistrationNavigationActivity;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.tracing.Tracer;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.util.Locale;
@@ -49,6 +50,7 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
@Override
protected final void onCreate(Bundle savedInstanceState) {
Tracer.getInstance().start(Log.tag(getClass()) + "#onCreate()");
this.networkAccess = new SignalServiceNetworkAccess(this);
onPreCreate();
@@ -61,6 +63,7 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
initializeClearKeyReceiver();
onCreate(savedInstanceState, true);
}
Tracer.getInstance().end(Log.tag(getClass()) + "#onCreate()");
}
protected void onPreCreate() {}

View File

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

View File

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

View File

@@ -3,11 +3,12 @@ package org.thoughtcrime.securesms;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.TaskStackBuilder;
import androidx.appcompat.app.AppCompatActivity;
import android.widget.Toast;
import androidx.core.app.TaskStackBuilder;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;

View File

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

View File

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

View File

@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms;
import android.Manifest;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

View File

@@ -2,7 +2,6 @@ package org.thoughtcrime.securesms;
import android.content.Context;
import android.graphics.PorterDuff.Mode;
import androidx.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -10,6 +9,8 @@ import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.util.List;

View File

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

View File

@@ -22,7 +22,6 @@ import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
@@ -32,7 +31,6 @@ import android.graphics.PorterDuff;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Vibrator;
import android.text.Html;
@@ -62,6 +60,7 @@ import androidx.appcompat.widget.SwitchCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.components.camera.CameraView;
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
@@ -71,7 +70,6 @@ import org.thoughtcrime.securesms.database.IdentityDatabase;
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobs.MultiDeviceVerifiedUpdateJob;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.qr.QrCode;
import org.thoughtcrime.securesms.qr.ScanListener;
@@ -87,18 +85,17 @@ import org.thoughtcrime.securesms.util.IdentityUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.WindowUtil;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.fingerprint.Fingerprint;
import org.whispersystems.libsignal.fingerprint.FingerprintParsingException;
import org.whispersystems.libsignal.fingerprint.FingerprintVersionMismatchException;
import org.whispersystems.libsignal.fingerprint.NumericFingerprintGenerator;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.Locale;
import java.util.UUID;
import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
@@ -228,9 +225,7 @@ public class VerifyIdentityActivity extends PassphraseRequiredActivity implement
private void setActionBarNotificationBarColor(MaterialColor color) {
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(color.toActionBarColor(this)));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(color.toStatusBarColor(this));
}
WindowUtil.setStatusBarColor(getWindow(), color.toStatusBarColor(this));
}
public static class VerifyDisplayFragment extends Fragment implements CompoundButton.OnCheckedChangeListener {

View File

@@ -19,6 +19,7 @@ package org.thoughtcrime.securesms;
import android.Manifest;
import android.app.PictureInPictureParams;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
@@ -32,39 +33,46 @@ import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProviders;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.components.TooltipPopup;
import org.thoughtcrime.securesms.components.webrtc.CallParticipantsListUpdatePopupWindow;
import org.thoughtcrime.securesms.components.webrtc.CallParticipantsState;
import org.thoughtcrime.securesms.components.webrtc.GroupCallSafetyNumberChangeNotificationUtil;
import org.thoughtcrime.securesms.components.webrtc.WebRtcAudioOutput;
import org.thoughtcrime.securesms.components.webrtc.WebRtcCallView;
import org.thoughtcrime.securesms.components.webrtc.WebRtcCallViewModel;
import org.thoughtcrime.securesms.components.webrtc.participantslist.CallParticipantsListDialog;
import org.thoughtcrime.securesms.conversation.ui.error.SafetyNumberChangeDialog;
import org.thoughtcrime.securesms.events.WebRtcViewModel;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.messagerequests.CalleeMustAcceptMessageRequestActivity;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.ringrtc.RemotePeer;
import org.thoughtcrime.securesms.service.WebRtcCallService;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.util.EllapsedTimeFormatter;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.signalservice.api.messages.calls.HangupMessage;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
import java.util.List;
public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumberChangeDialog.Callback {
private static final String TAG = WebRtcCallActivity.class.getSimpleName();
private static final int STANDARD_DELAY_FINISH = 1000;
private static final int STANDARD_DELAY_FINISH = 1000;
public static final String ANSWER_ACTION = WebRtcCallActivity.class.getCanonicalName() + ".ANSWER_ACTION";
public static final String DENY_ACTION = WebRtcCallActivity.class.getCanonicalName() + ".DENY_ACTION";
@@ -72,11 +80,19 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
public static final String EXTRA_ENABLE_VIDEO_IF_AVAILABLE = WebRtcCallActivity.class.getCanonicalName() + ".ENABLE_VIDEO_IF_AVAILABLE";
private CallParticipantsListUpdatePopupWindow participantUpdateWindow;
private WebRtcCallView callScreen;
private TooltipPopup videoTooltip;
private WebRtcCallViewModel viewModel;
private boolean enableVideoIfAvailable;
@Override
protected void attachBaseContext(@NonNull Context newBase) {
getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES);
super.attachBaseContext(newBase);
}
@Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "onCreate()");
@@ -127,9 +143,11 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
EventBus.getDefault().unregister(this);
}
CallParticipantsState state = viewModel.getCallParticipantsState().getValue();
if (state != null && state.getCallState() == WebRtcViewModel.State.CALL_PRE_JOIN) {
finish();
if (!viewModel.isCallingStarted()) {
CallParticipantsState state = viewModel.getCallParticipantsState().getValue();
if (state != null && state.getCallState() == WebRtcViewModel.State.CALL_PRE_JOIN) {
finish();
}
}
}
@@ -140,11 +158,13 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
EventBus.getDefault().unregister(this);
CallParticipantsState state = viewModel.getCallParticipantsState().getValue();
if (state != null && state.getCallState() == WebRtcViewModel.State.CALL_PRE_JOIN) {
Intent intent = new Intent(this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_CANCEL_PRE_JOIN_CALL);
startService(intent);
if (!viewModel.isCallingStarted()) {
CallParticipantsState state = viewModel.getCallParticipantsState().getValue();
if (state != null && state.getCallState() == WebRtcViewModel.State.CALL_PRE_JOIN) {
Intent intent = new Intent(this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_CANCEL_PRE_JOIN_CALL);
startService(intent);
}
}
}
@@ -168,6 +188,7 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) {
viewModel.setIsInPipMode(isInPictureInPictureMode);
participantUpdateWindow.setEnabled(!isInPictureInPictureMode);
}
private boolean enterPipModeIfPossible() {
@@ -176,6 +197,8 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
.setAspectRatio(new Rational(9, 16))
.build();
enterPictureInPictureMode(params);
CallParticipantsListDialog.dismiss(getSupportFragmentManager());
return true;
}
return false;
@@ -207,6 +230,8 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
private void initializeResources() {
callScreen = findViewById(R.id.callScreen);
callScreen.setControlsListener(new ControlsListener());
participantUpdateWindow = new CallParticipantsListUpdatePopupWindow(callScreen);
}
private void initializeViewModel() {
@@ -217,33 +242,53 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
viewModel.getEvents().observe(this, this::handleViewModelEvent);
viewModel.getCallTime().observe(this, this::handleCallTime);
viewModel.getCallParticipantsState().observe(this, callScreen::updateCallParticipants);
viewModel.getCallParticipantListUpdate().observe(this, participantUpdateWindow::addCallParticipantListUpdate);
viewModel.getSafetyNumberChangeEvent().observe(this, this::handleSafetyNumberChangeEvent);
viewModel.getGroupMembers().observe(this, unused -> updateGroupMembersForGroupCall());
viewModel.shouldShowSpeakerHint().observe(this, this::updateSpeakerHint);
callScreen.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
CallParticipantsState state = viewModel.getCallParticipantsState().getValue();
if (state != null) {
if (state.needsNewRequestSizes()) {
Intent intent = new Intent(WebRtcCallActivity.this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_GROUP_UPDATE_RENDERED_RESOLUTIONS);
startService(intent);
}
}
});
}
private void handleViewModelEvent(@NonNull WebRtcCallViewModel.Event event) {
if (event instanceof WebRtcCallViewModel.Event.StartCall) {
startCall(((WebRtcCallViewModel.Event.StartCall)event).isVideoCall());
return;
} else if (event instanceof WebRtcCallViewModel.Event.ShowGroupCallSafetyNumberChange) {
SafetyNumberChangeDialog.showForGroupCall(getSupportFragmentManager(), ((WebRtcCallViewModel.Event.ShowGroupCallSafetyNumberChange) event).getIdentityRecords());
return;
}
if (isInPipMode()) {
return;
}
switch (event) {
case SHOW_VIDEO_TOOLTIP:
if (videoTooltip == null) {
videoTooltip = TooltipPopup.forTarget(callScreen.getVideoTooltipTarget())
.setBackgroundTint(ContextCompat.getColor(this, R.color.core_ultramarine))
.setTextColor(ContextCompat.getColor(this, R.color.core_white))
.setText(R.string.WebRtcCallActivity__tap_here_to_turn_on_your_video)
.setOnDismissListener(() -> viewModel.onDismissedVideoTooltip())
.show(TooltipPopup.POSITION_ABOVE);
return;
}
break;
case DISMISS_VIDEO_TOOLTIP:
if (videoTooltip != null) {
videoTooltip.dismiss();
videoTooltip = null;
}
break;
default:
throw new IllegalArgumentException("Unknown event: " + event);
if (event instanceof WebRtcCallViewModel.Event.ShowVideoTooltip) {
if (videoTooltip == null) {
videoTooltip = TooltipPopup.forTarget(callScreen.getVideoTooltipTarget())
.setBackgroundTint(ContextCompat.getColor(this, R.color.core_ultramarine))
.setTextColor(ContextCompat.getColor(this, R.color.core_white))
.setText(R.string.WebRtcCallActivity__tap_here_to_turn_on_your_video)
.setOnDismissListener(() -> viewModel.onDismissedVideoTooltip())
.show(TooltipPopup.POSITION_ABOVE);
return;
}
} else if (event instanceof WebRtcCallViewModel.Event.DismissVideoTooltip) {
if (videoTooltip != null) {
videoTooltip.dismiss();
videoTooltip = null;
}
} else {
throw new IllegalArgumentException("Unknown event: " + event);
}
}
@@ -381,8 +426,12 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
startService(intent);
}
private void handleOutgoingCall() {
callScreen.setStatus(getString(R.string.WebRtcCallActivity__calling));
private void handleOutgoingCall(@NonNull WebRtcViewModel event) {
if (event.getGroupState().isNotIdle()) {
callScreen.setStatusFromGroupCallState(event.getGroupState());
} else {
callScreen.setStatus(getString(R.string.WebRtcCallActivity__calling));
}
}
private void handleTerminate(@NonNull Recipient recipient, @NonNull HangupMessage.Type hangupType) {
@@ -408,8 +457,11 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
delayedFinish(WebRtcCallService.BUSY_TONE_LENGTH);
}
private void handleCallConnected() {
private void handleCallConnected(@NonNull WebRtcViewModel event) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES);
if (event.getGroupState().isNotIdleOrConnected()) {
callScreen.setStatusFromGroupCallState(event.getGroupState());
}
}
private void handleRecipientUnavailable() {
@@ -428,7 +480,7 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
if (isFinishing()) return; // XXX Stuart added this check above, not sure why, so I'm repeating in ignorance. - moxie
new AlertDialog.Builder(this)
.setTitle(R.string.RedPhone_number_not_registered)
.setIconAttribute(R.attr.dialog_alert_icon)
.setIcon(R.drawable.ic_warning)
.setMessage(R.string.RedPhone_the_number_you_dialed_does_not_support_secure_voice)
.setCancelable(true)
.setPositiveButton(R.string.RedPhone_got_it, (d, w) -> handleTerminate(event.getRecipient(), HangupMessage.Type.NORMAL))
@@ -447,14 +499,40 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
SafetyNumberChangeDialog.showForCall(getSupportFragmentManager(), recipient.getId());
}
@Override
public void onSendAnywayAfterSafetyNumberChange() {
Intent intent = new Intent(WebRtcCallActivity.this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_OUTGOING_CALL)
.putExtra(WebRtcCallService.EXTRA_REMOTE_PEER, new RemotePeer(viewModel.getRecipient().getId()))
.putExtra(WebRtcCallService.EXTRA_OFFER_TYPE, OfferMessage.Type.AUDIO_CALL.getCode());
public void handleSafetyNumberChangeEvent(@NonNull WebRtcCallViewModel.SafetyNumberChangeEvent safetyNumberChangeEvent) {
if (Util.hasItems(safetyNumberChangeEvent.getRecipientIds())) {
if (safetyNumberChangeEvent.isInPipMode()) {
GroupCallSafetyNumberChangeNotificationUtil.showNotification(this, viewModel.getRecipient().get());
} else {
GroupCallSafetyNumberChangeNotificationUtil.cancelNotification(this, viewModel.getRecipient().get());
SafetyNumberChangeDialog.showForDuringGroupCall(getSupportFragmentManager(), safetyNumberChangeEvent.getRecipientIds());
}
}
}
startService(intent);
private void updateGroupMembersForGroupCall() {
startService(new Intent(this, WebRtcCallService.class).setAction(WebRtcCallService.ACTION_GROUP_REQUEST_UPDATE_MEMBERS));
}
private void updateSpeakerHint(boolean showSpeakerHint) {
if (showSpeakerHint) {
callScreen.showSpeakerViewHint();
} else {
callScreen.hideSpeakerViewHint();
}
}
@Override
public void onSendAnywayAfterSafetyNumberChange(@NonNull List<RecipientId> changedRecipients) {
CallParticipantsState state = viewModel.getCallParticipantsState().getValue();
if (state.getGroupCallState().isConnected()) {
Intent intent = new Intent(this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_GROUP_APPROVE_SAFETY_CHANGE)
.putExtra(WebRtcCallService.EXTRA_RECIPIENT_IDS, RecipientId.toSerializedList(changedRecipients));
startService(intent);
} else {
startCall(state.getLocalParticipant().isVideoEnabled());
}
}
@Override
@@ -462,7 +540,19 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
@Override
public void onCanceled() {
handleTerminate(viewModel.getRecipient().get(), HangupMessage.Type.NORMAL);
CallParticipantsState state = viewModel.getCallParticipantsState().getValue();
if (state != null && state.getGroupCallState().isNotIdle()) {
if (state.getCallState() == WebRtcViewModel.State.CALL_PRE_JOIN) {
Intent intent = new Intent(this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_CANCEL_PRE_JOIN_CALL);
startService(intent);
finish();
} else {
handleEndCall();
}
} else {
handleTerminate(viewModel.getRecipient().get(), HangupMessage.Type.NORMAL);
}
}
private boolean isSystemPipEnabledAndAvailable() {
@@ -486,7 +576,8 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
callScreen.setRecipient(event.getRecipient());
switch (event.getState()) {
case CALL_CONNECTED: handleCallConnected(); break;
case CALL_PRE_JOIN: handleCallPreJoin(event); break;
case CALL_CONNECTED: handleCallConnected(event); break;
case NETWORK_FAILURE: handleServerFailure(); break;
case CALL_RINGING: handleCallRinging(); break;
case CALL_DISCONNECTED: handleTerminate(event.getRecipient(), HangupMessage.Type.NORMAL); break;
@@ -496,7 +587,7 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
case CALL_NEEDS_PERMISSION: handleTerminate(event.getRecipient(), HangupMessage.Type.NEED_PERMISSION); break;
case NO_SUCH_USER: handleNoSuchUser(event); break;
case RECIPIENT_UNAVAILABLE: handleRecipientUnavailable(); break;
case CALL_OUTGOING: handleOutgoingCall(); break;
case CALL_OUTGOING: handleOutgoingCall(event); break;
case CALL_BUSY: handleCallBusy(); break;
case UNTRUSTED_IDENTITY: handleUntrustedIdentity(event); break;
}
@@ -511,19 +602,29 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
}
}
private void handleCallPreJoin(@NonNull WebRtcViewModel event) {
if (event.getGroupState().isNotIdle()) {
callScreen.setStatusFromGroupCallState(event.getGroupState());
}
}
private void startCall(boolean isVideoCall) {
enableVideoIfAvailable = isVideoCall;
Intent intent = new Intent(WebRtcCallActivity.this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_OUTGOING_CALL)
.putExtra(WebRtcCallService.EXTRA_REMOTE_PEER, new RemotePeer(viewModel.getRecipient().getId()))
.putExtra(WebRtcCallService.EXTRA_OFFER_TYPE, (isVideoCall ? OfferMessage.Type.VIDEO_CALL : OfferMessage.Type.AUDIO_CALL).getCode());
startService(intent);
MessageSender.onMessageSent();
}
private final class ControlsListener implements WebRtcCallView.ControlsListener {
@Override
public void onStartCall(boolean isVideoCall) {
enableVideoIfAvailable = isVideoCall;
Intent intent = new Intent(WebRtcCallActivity.this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_OUTGOING_CALL)
.putExtra(WebRtcCallService.EXTRA_REMOTE_PEER, new RemotePeer(viewModel.getRecipient().getId()))
.putExtra(WebRtcCallService.EXTRA_OFFER_TYPE, (isVideoCall ? OfferMessage.Type.VIDEO_CALL : OfferMessage.Type.AUDIO_CALL).getCode());
startService(intent);
MessageSender.onMessageSent();
viewModel.startCall(isVideoCall);
}
@Override
@@ -604,5 +705,4 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
viewModel.setIsViewingFocusedParticipant(page);
}
}
}

View File

@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.attachments;
import android.net.Uri;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.database.AttachmentDatabase;

View File

@@ -1,10 +1,10 @@
package org.thoughtcrime.securesms.attachments;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.audio.AudioHash;
import org.thoughtcrime.securesms.blurhash.BlurHash;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.stickers.StickerLocator;

View File

@@ -8,8 +8,9 @@ import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.MediaRecorder;
import android.os.Build;
import org.thoughtcrime.securesms.logging.Log;
import org.signal.core.util.StreamUtil;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.util.Util;
import java.io.IOException;
@@ -81,7 +82,7 @@ public class AudioCodec {
mediaCodec.release();
audioRecord.release();
Util.close(outputStream);
StreamUtil.close(outputStream);
setFinished();
}
}

View File

@@ -5,15 +5,16 @@ import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.logging.Log;
import androidx.annotation.NonNull;
import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import org.whispersystems.libsignal.util.Pair;
import java.io.IOException;

View File

@@ -16,18 +16,18 @@ import androidx.core.util.Consumer;
import com.google.protobuf.ByteString;
import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.model.databaseprotos.AudioWaveFormData;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.media.DecryptableUriMediaInput;
import org.thoughtcrime.securesms.media.MediaInput;
import org.thoughtcrime.securesms.mms.AudioSlide;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.concurrent.SerialExecutor;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import java.io.IOException;
import java.nio.ByteBuffer;

View File

@@ -22,9 +22,9 @@ import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.registration.fragments.RestoreBackupFragment;
import org.thoughtcrime.securesms.service.LocalBackupListener;
import org.thoughtcrime.securesms.util.BackupUtil;

View File

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

View File

@@ -6,8 +6,8 @@ import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.crypto.KeyStoreHelper;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
/**

View File

@@ -12,12 +12,13 @@ import androidx.documentfile.provider.DocumentFile;
import com.annimon.stream.function.Consumer;
import com.annimon.stream.function.Predicate;
import com.google.android.collect.Sets;
import com.google.protobuf.ByteString;
import net.sqlcipher.database.SQLiteDatabase;
import org.greenrobot.eventbus.EventBus;
import org.signal.core.util.Conversions;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.attachments.AttachmentId;
import org.thoughtcrime.securesms.crypto.AttachmentSecret;
import org.thoughtcrime.securesms.crypto.ClassicDecryptingPartInputStream;
@@ -35,9 +36,8 @@ import org.thoughtcrime.securesms.database.SessionDatabase;
import org.thoughtcrime.securesms.database.SignedPreKeyDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.StickerDatabase;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.util.Conversions;
import org.thoughtcrime.securesms.util.SetUtil;
import org.thoughtcrime.securesms.util.Stopwatch;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.kdf.HKDFv3;
@@ -69,7 +69,7 @@ public class FullBackupExporter extends FullBackupBase {
@SuppressWarnings("unused")
private static final String TAG = FullBackupExporter.class.getSimpleName();
private static final Set<String> BLACKLISTED_TABLES = Sets.newHashSet(
private static final Set<String> BLACKLISTED_TABLES = SetUtil.newHashSet(
SignedPreKeyDatabase.TABLE_NAME,
OneTimePreKeyDatabase.TABLE_NAME,
SessionDatabase.TABLE_NAME,

View File

@@ -14,6 +14,9 @@ import androidx.annotation.NonNull;
import net.sqlcipher.database.SQLiteDatabase;
import org.greenrobot.eventbus.EventBus;
import org.signal.core.util.Conversions;
import org.signal.core.util.StreamUtil;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.backup.BackupProtos.Attachment;
import org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame;
import org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion;
@@ -25,13 +28,10 @@ import org.thoughtcrime.securesms.crypto.ModernEncryptingPartOutputStream;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.SearchDatabase;
import org.thoughtcrime.securesms.database.StickerDatabase;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.BackupUtil;
import org.thoughtcrime.securesms.util.Conversions;
import org.thoughtcrime.securesms.util.SqlUtil;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.kdf.HKDFv3;
import org.whispersystems.libsignal.util.ByteUtil;
@@ -237,11 +237,11 @@ public class FullBackupImporter extends FullBackupBase {
this.in = in;
byte[] headerLengthBytes = new byte[4];
Util.readFully(in, headerLengthBytes);
StreamUtil.readFully(in, headerLengthBytes);
int headerLength = Conversions.byteArrayToInt(headerLengthBytes);
byte[] headerFrame = new byte[headerLength];
Util.readFully(in, headerFrame);
StreamUtil.readFully(in, headerFrame);
BackupFrame frame = BackupFrame.parseFrom(headerFrame);
@@ -313,7 +313,7 @@ public class FullBackupImporter extends FullBackupBase {
byte[] theirMac = new byte[10];
try {
Util.readFully(in, theirMac);
StreamUtil.readFully(in, theirMac);
} catch (IOException e) {
throw new IOException(e);
}
@@ -329,10 +329,10 @@ public class FullBackupImporter extends FullBackupBase {
private BackupFrame readFrame(InputStream in) throws IOException {
try {
byte[] length = new byte[4];
Util.readFully(in, length);
StreamUtil.readFully(in, length);
byte[] frame = new byte[Conversions.byteArrayToInt(length)];
Util.readFully(in, frame);
StreamUtil.readFully(in, frame);
byte[] theirMac = new byte[10];
System.arraycopy(frame, frame.length - 10, theirMac, 0, theirMac.length);

View File

@@ -0,0 +1,171 @@
package org.thoughtcrime.securesms.blocked;
import android.app.AlertDialog;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.ViewSwitcher;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProviders;
import com.google.android.material.snackbar.Snackbar;
import org.thoughtcrime.securesms.ContactSelectionListFragment;
import org.thoughtcrime.securesms.PassphraseRequiredActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.ContactFilterToolbar;
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.whispersystems.libsignal.util.guava.Optional;
public class BlockedUsersActivity extends PassphraseRequiredActivity implements BlockedUsersFragment.Listener, ContactSelectionListFragment.OnContactSelectedListener {
private static final String CONTACT_SELECTION_FRAGMENT = "Contact.Selection.Fragment";
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
private BlockedUsersViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState, boolean ready) {
super.onCreate(savedInstanceState, ready);
dynamicTheme.onCreate(this);
setContentView(R.layout.blocked_users_activity);
BlockedUsersRepository repository = new BlockedUsersRepository(this);
BlockedUsersViewModel.Factory factory = new BlockedUsersViewModel.Factory(repository);
viewModel = ViewModelProviders.of(this, factory).get(BlockedUsersViewModel.class);
ViewSwitcher viewSwitcher = findViewById(R.id.toolbar_switcher);
Toolbar toolbar = findViewById(R.id.toolbar);
ContactFilterToolbar contactFilterToolbar = findViewById(R.id.filter_toolbar);
View container = findViewById(R.id.fragment_container);
toolbar.setNavigationOnClickListener(unused -> onBackPressed());
contactFilterToolbar.setNavigationOnClickListener(unused -> onBackPressed());
contactFilterToolbar.setOnFilterChangedListener(query -> {
Fragment fragment = getSupportFragmentManager().findFragmentByTag(CONTACT_SELECTION_FRAGMENT);
if (fragment != null) {
((ContactSelectionListFragment) fragment).setQueryFilter(query);
}
});
contactFilterToolbar.setHint(R.string.BlockedUsersActivity__add_blocked_user);
//noinspection CodeBlock2Expr
getSupportFragmentManager().addOnBackStackChangedListener(() -> {
viewSwitcher.setDisplayedChild(getSupportFragmentManager().getBackStackEntryCount());
if (getSupportFragmentManager().getBackStackEntryCount() == 1) {
contactFilterToolbar.focusAndShowKeyboard();
}
});
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, new BlockedUsersFragment())
.commit();
viewModel.getEvents().observe(this, event -> handleEvent(container, event));
}
@Override
protected void onResume() {
super.onResume();
dynamicTheme.onResume(this);
}
@Override
public boolean onBeforeContactSelected(Optional<RecipientId> recipientId, String number) {
final String displayName = recipientId.transform(id -> Recipient.resolved(id).getDisplayName(this)).or(number);
AlertDialog confirmationDialog = new AlertDialog.Builder(BlockedUsersActivity.this)
.setTitle(R.string.BlockedUsersActivity__block_user)
.setMessage(getString(R.string.BlockedUserActivity__s_will_not_be_able_to, displayName))
.setPositiveButton(R.string.BlockedUsersActivity__block, (dialog, which) -> {
if (recipientId.isPresent()) {
viewModel.block(recipientId.get());
} else {
viewModel.createAndBlock(number);
}
dialog.dismiss();
onBackPressed();
})
.setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.dismiss())
.setCancelable(true)
.create();
confirmationDialog.setOnShowListener(dialog -> {
confirmationDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(Color.RED);
});
confirmationDialog.show();
return false;
}
@Override
public void onContactDeselected(Optional<RecipientId> recipientId, String number) {
}
@Override
public void handleAddUserToBlockedList() {
ContactSelectionListFragment fragment = new ContactSelectionListFragment();
Intent intent = getIntent();
fragment.setOnContactSelectedListener(this);
intent.putExtra(ContactSelectionListFragment.REFRESHABLE, false);
intent.putExtra(ContactSelectionListFragment.SELECTION_LIMITS, 1);
intent.putExtra(ContactSelectionListFragment.HIDE_COUNT, true);
intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE,
ContactsCursorLoader.DisplayMode.FLAG_PUSH |
ContactsCursorLoader.DisplayMode.FLAG_SMS |
ContactsCursorLoader.DisplayMode.FLAG_ACTIVE_GROUPS |
ContactsCursorLoader.DisplayMode.FLAG_INACTIVE_GROUPS |
ContactsCursorLoader.DisplayMode.FLAG_BLOCK);
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment, CONTACT_SELECTION_FRAGMENT)
.addToBackStack(null)
.commit();
}
private void handleEvent(@NonNull View view, @NonNull BlockedUsersViewModel.Event event) {
final String displayName;
if (event.getRecipient() == null) {
displayName = event.getNumber();
} else {
displayName = event.getRecipient().getDisplayName(this);
}
final @StringRes int messageResId;
switch (event.getEventType()) {
case BLOCK_SUCCEEDED:
messageResId = R.string.BlockedUsersActivity__s_has_been_blocked;
break;
case BLOCK_FAILED:
messageResId = R.string.BlockedUsersActivity__failed_to_block_s;
break;
case UNBLOCK_SUCCEEDED:
messageResId = R.string.BlockedUsersActivity__s_has_been_unblocked;
break;
default:
throw new IllegalArgumentException("Unsupported event type " + event);
}
Snackbar.make(view, getString(messageResId, displayName), Snackbar.LENGTH_SHORT).show();
}
}

View File

@@ -0,0 +1,96 @@
package org.thoughtcrime.securesms.blocked;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.util.Consumer;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;
import androidx.recyclerview.widget.RecyclerView;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.recipients.Recipient;
import java.util.Objects;
final class BlockedUsersAdapter extends ListAdapter<Recipient, BlockedUsersAdapter.ViewHolder> {
private final RecipientClickedListener recipientClickedListener;
BlockedUsersAdapter(@NonNull RecipientClickedListener recipientClickedListener) {
super(new RecipientDiffCallback());
this.recipientClickedListener = recipientClickedListener;
}
@Override
public @NonNull ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.blocked_users_adapter_item, parent, false),
position -> recipientClickedListener.onRecipientClicked(Objects.requireNonNull(getItem(position))));
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.bind(Objects.requireNonNull(getItem(position)));
}
static final class ViewHolder extends RecyclerView.ViewHolder {
private final AvatarImageView avatar;
private final TextView displayName;
private final TextView numberOrUsername;
public ViewHolder(@NonNull View itemView, Consumer<Integer> clickConsumer) {
super(itemView);
this.avatar = itemView.findViewById(R.id.avatar);
this.displayName = itemView.findViewById(R.id.display_name);
this.numberOrUsername = itemView.findViewById(R.id.number_or_username);
itemView.setOnClickListener(unused -> {
if (getAdapterPosition() != RecyclerView.NO_POSITION) {
clickConsumer.accept(getAdapterPosition());
}
});
}
public void bind(@NonNull Recipient recipient) {
avatar.setAvatar(recipient);
displayName.setText(recipient.getDisplayName(itemView.getContext()));
if (recipient.hasAUserSetDisplayName(itemView.getContext())) {
String identifier = recipient.getE164().or(recipient.getUsername()).orNull();
if (identifier != null) {
numberOrUsername.setText(identifier);
numberOrUsername.setVisibility(View.VISIBLE);
} else {
numberOrUsername.setVisibility(View.GONE);
}
} else {
numberOrUsername.setVisibility(View.GONE);
}
}
}
private static final class RecipientDiffCallback extends DiffUtil.ItemCallback<Recipient> {
@Override
public boolean areItemsTheSame(@NonNull Recipient oldItem, @NonNull Recipient newItem) {
return oldItem.equals(newItem);
}
@Override
public boolean areContentsTheSame(@NonNull Recipient oldItem, @NonNull Recipient newItem) {
return oldItem.equals(newItem);
}
}
interface RecipientClickedListener {
void onRecipientClicked(@NonNull Recipient recipient);
}
}

View File

@@ -0,0 +1,100 @@
package org.thoughtcrime.securesms.blocked;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.RecyclerView;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.recipients.Recipient;
public class BlockedUsersFragment extends Fragment {
private BlockedUsersViewModel viewModel;
private Listener listener;
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (context instanceof Listener) {
listener = (Listener) context;
} else {
throw new ClassCastException("Expected context to implement Listener");
}
}
@Override
public void onDetach() {
super.onDetach();
listener = null;
}
@Override
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.blocked_users_fragment, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
View addUser = view.findViewById(R.id.add_blocked_user_touch_target);
RecyclerView recycler = view.findViewById(R.id.blocked_users_recycler);
View empty = view.findViewById(R.id.no_blocked_users);
BlockedUsersAdapter adapter = new BlockedUsersAdapter(this::handleRecipientClicked);
recycler.setAdapter(adapter);
addUser.setOnClickListener(unused -> {
if (listener != null) {
listener.handleAddUserToBlockedList();
}
});
viewModel = ViewModelProviders.of(requireActivity()).get(BlockedUsersViewModel.class);
viewModel.getRecipients().observe(getViewLifecycleOwner(), list -> {
if (list.isEmpty()) {
empty.setVisibility(View.VISIBLE);
} else {
empty.setVisibility(View.GONE);
}
adapter.submitList(list);
});
}
private void handleRecipientClicked(@NonNull Recipient recipient) {
AlertDialog confirmationDialog = new AlertDialog.Builder(requireContext())
.setTitle(R.string.BlockedUsersActivity__unblock_user)
.setMessage(getString(R.string.BlockedUsersActivity__do_you_want_to_unblock_s, recipient.getDisplayName(requireContext())))
.setPositiveButton(R.string.BlockedUsersActivity__unblock, (dialog, which) -> {
viewModel.unblock(recipient.getId());
dialog.dismiss();
})
.setNegativeButton(android.R.string.cancel, (dialog, which) -> {
dialog.dismiss();
})
.setCancelable(true)
.create();
confirmationDialog.setOnShowListener(dialog -> {
confirmationDialog.getButton(DialogInterface.BUTTON_POSITIVE).setTextColor(Color.RED);
});
confirmationDialog.show();
}
interface Listener {
void handleAddUserToBlockedList();
}
}

View File

@@ -0,0 +1,76 @@
package org.thoughtcrime.securesms.blocked;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.core.util.Consumer;
import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
class BlockedUsersRepository {
private static final String TAG = Log.tag(BlockedUsersRepository.class);
private final Context context;
BlockedUsersRepository(@NonNull Context context) {
this.context = context;
}
void getBlocked(@NonNull Consumer<List<Recipient>> blockedUsers) {
SignalExecutors.BOUNDED.execute(() -> {
RecipientDatabase db = DatabaseFactory.getRecipientDatabase(context);
try (RecipientDatabase.RecipientReader reader = db.readerForBlocked(db.getBlocked())) {
int count = reader.getCount();
if (count == 0) {
blockedUsers.accept(Collections.emptyList());
} else {
List<Recipient> recipients = new ArrayList<>();
while (reader.getNext() != null) {
recipients.add(reader.getCurrent());
}
blockedUsers.accept(recipients);
}
}
});
}
void block(@NonNull RecipientId recipientId, @NonNull Runnable success, @NonNull Runnable failure) {
SignalExecutors.BOUNDED.execute(() -> {
try {
RecipientUtil.block(context, Recipient.resolved(recipientId));
success.run();
} catch (IOException | GroupChangeFailedException | GroupChangeBusyException e) {
Log.w(TAG, "block: failed to block recipient: ", e);
failure.run();
}
});
}
void createAndBlock(@NonNull String number, @NonNull Runnable success) {
SignalExecutors.BOUNDED.execute(() -> {
RecipientUtil.blockNonGroup(context, Recipient.external(context, number));
success.run();
});
}
void unblock(@NonNull RecipientId recipientId, @NonNull Runnable success) {
SignalExecutors.BOUNDED.execute(() -> {
RecipientUtil.unblock(context, Recipient.resolved(recipientId));
success.run();
});
}
}

View File

@@ -0,0 +1,115 @@
package org.thoughtcrime.securesms.blocked;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.SingleLiveEvent;
import java.util.List;
import java.util.Objects;
public class BlockedUsersViewModel extends ViewModel {
private final BlockedUsersRepository repository;
private final MutableLiveData<List<Recipient>> recipients;
private final SingleLiveEvent<Event> events = new SingleLiveEvent<>();
private BlockedUsersViewModel(@NonNull BlockedUsersRepository repository) {
this.repository = repository;
this.recipients = new MutableLiveData<>();
loadRecipients();
}
public LiveData<List<Recipient>> getRecipients() {
return recipients;
}
public LiveData<Event> getEvents() {
return events;
}
void block(@NonNull RecipientId recipientId) {
repository.block(recipientId,
() -> {
loadRecipients();
events.postValue(new Event(EventType.BLOCK_SUCCEEDED, Recipient.resolved(recipientId)));
},
() -> events.postValue(new Event(EventType.BLOCK_FAILED, Recipient.resolved(recipientId))));
}
void createAndBlock(@NonNull String number) {
repository.createAndBlock(number, () -> {
loadRecipients();
events.postValue(new Event(EventType.BLOCK_SUCCEEDED, number));
});
}
void unblock(@NonNull RecipientId recipientId) {
repository.unblock(recipientId, () -> {
loadRecipients();
events.postValue(new Event(EventType.UNBLOCK_SUCCEEDED, Recipient.resolved(recipientId)));
});
}
private void loadRecipients() {
repository.getBlocked(recipients::postValue);
}
enum EventType {
BLOCK_SUCCEEDED,
BLOCK_FAILED,
UNBLOCK_SUCCEEDED
}
public static final class Event {
private final EventType eventType;
private final Recipient recipient;
private final String number;
private Event(@NonNull EventType eventType, @NonNull Recipient recipient) {
this.eventType = eventType;
this.recipient = recipient;
this.number = null;
}
private Event(@NonNull EventType eventType, @NonNull String number) {
this.eventType = eventType;
this.recipient = null;
this.number = number;
}
public @Nullable Recipient getRecipient() {
return recipient;
}
public @Nullable String getNumber() {
return number;
}
public @NonNull EventType getEventType() {
return eventType;
}
}
public static class Factory implements ViewModelProvider.Factory {
private final BlockedUsersRepository repository;
public Factory(@NonNull BlockedUsersRepository repository) {
this.repository = repository;
}
@Override
public @NonNull <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
return Objects.requireNonNull(modelClass.cast(new BlockedUsersViewModel(repository)));
}
}
}

View File

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

View File

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

View File

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

View File

@@ -4,7 +4,6 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build.VERSION_CODES;
import androidx.core.content.ContextCompat;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;

View File

@@ -371,10 +371,11 @@ public final class AudioView extends FrameLayout {
}
private void showPlayButton() {
if (!smallView || seekBar.getProgress() == 0) {
if (!smallView) {
circleProgress.setVisibility(GONE);
} else if (seekBar.getProgress() == 0) {
circleProgress.setInstantProgress(1);
}
circleProgress.setVisibility(GONE);
playPauseButton.setVisibility(VISIBLE);
controlToggle.displayQuick(progressAndPlay);
}

View File

@@ -19,6 +19,7 @@ import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
import org.thoughtcrime.securesms.groups.ui.managegroup.ManageGroupActivity;
import org.thoughtcrime.securesms.mms.GlideApp;
@@ -132,9 +133,23 @@ public final class AvatarImageView extends AppCompatImageView {
setAvatar(GlideApp.with(this), recipient, false);
}
/**
* Shows self as the profile avatar.
*/
public void setAvatarUsingProfile(@Nullable Recipient recipient) {
setAvatar(GlideApp.with(this), recipient, false, true);
}
public void setAvatar(@NonNull GlideRequests requestManager, @Nullable Recipient recipient, boolean quickContactEnabled) {
setAvatar(requestManager, recipient, quickContactEnabled, false);
}
public void setAvatar(@NonNull GlideRequests requestManager, @Nullable Recipient recipient, boolean quickContactEnabled, boolean useSelfProfileAvatar) {
if (recipient != null) {
RecipientContactPhoto photo = new RecipientContactPhoto(recipient);
RecipientContactPhoto photo = (recipient.isSelf() && useSelfProfileAvatar) ? new RecipientContactPhoto(recipient,
new ProfileContactPhoto(Recipient.self(),
Recipient.self().getProfileAvatar()))
: new RecipientContactPhoto(recipient);
if (!photo.equals(recipientContactPhoto)) {
requestManager.clear(this);
@@ -218,9 +233,13 @@ public final class AvatarImageView extends AppCompatImageView {
private final boolean ready;
RecipientContactPhoto(@NonNull Recipient recipient) {
this(recipient, recipient.getContactPhoto());
}
RecipientContactPhoto(@NonNull Recipient recipient, @Nullable ContactPhoto contactPhoto) {
this.recipient = recipient;
this.ready = !recipient.isResolving();
this.contactPhoto = recipient.getContactPhoto();
this.contactPhoto = contactPhoto;
}
public boolean equals(@Nullable RecipientContactPhoto other) {

View File

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

View File

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

View File

@@ -21,10 +21,12 @@ import android.view.inputmethod.InputConnection;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.view.inputmethod.EditorInfoCompat;
import androidx.core.view.inputmethod.InputConnectionCompat;
import androidx.core.view.inputmethod.InputContentInfoCompat;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.TransportOption;
import org.thoughtcrime.securesms.components.emoji.EmojiEditText;
@@ -33,12 +35,9 @@ import org.thoughtcrime.securesms.components.mention.MentionDeleter;
import org.thoughtcrime.securesms.components.mention.MentionRendererDelegate;
import org.thoughtcrime.securesms.components.mention.MentionValidatorWatcher;
import org.thoughtcrime.securesms.database.model.Mention;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.StringUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ThemeUtil;
import java.util.List;
@@ -257,7 +256,7 @@ public class ComposeText extends EmojiEditText {
setImeOptions(getImeOptions() | 16777216);
}
mentionRendererDelegate = new MentionRendererDelegate(getContext(), ThemeUtil.getThemedColor(getContext(), R.attr.conversation_mention_background_color));
mentionRendererDelegate = new MentionRendererDelegate(getContext(), ContextCompat.getColor(getContext(), R.color.conversation_mention_background_color));
addTextChangedListener(new MentionDeleter());
mentionValidatorWatcher = new MentionValidatorWatcher();

View File

@@ -19,6 +19,7 @@ import androidx.core.widget.TextViewCompat;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.views.DarkOverflowToolbar;
public final class ContactFilterToolbar extends DarkOverflowToolbar {
@@ -125,6 +126,10 @@ public final class ContactFilterToolbar extends DarkOverflowToolbar {
attributes.recycle();
}
public void focusAndShowKeyboard() {
ViewUtil.focusAndShowKeyboard(searchText);
}
public void clear() {
searchText.setText("");
notifyListener();

View File

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

View File

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

View File

@@ -3,13 +3,15 @@ package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import android.widget.ImageView;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import android.widget.ImageView;
import androidx.core.content.ContextCompat;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.attachments.Attachment;
@@ -17,7 +19,6 @@ import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideClickListener;
import org.thoughtcrime.securesms.mms.SlidesClickedListener;
import org.thoughtcrime.securesms.util.ThemeUtil;
import java.util.List;
@@ -57,7 +58,7 @@ public class ConversationItemThumbnail extends FrameLayout {
this.cornerMask = new CornerMask(this);
this.outliner = new Outliner();
outliner.setColor(ThemeUtil.getThemedColor(getContext(), R.attr.conversation_item_image_outline_color));
outliner.setColor(ContextCompat.getColor(getContext(), R.color.signal_inverse_transparent_20));
if (attrs != null) {
TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.ConversationItemThumbnail, 0, 0);

View File

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

View File

@@ -2,12 +2,13 @@ package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.graphics.PorterDuff;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient;

View File

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

View File

@@ -4,15 +4,10 @@ import android.app.Dialog;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.DialogPreference;
import androidx.preference.PreferenceDialogFragmentCompat;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import org.thoughtcrime.securesms.logging.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
@@ -20,6 +15,12 @@ import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.DialogPreference;
import androidx.preference.PreferenceDialogFragmentCompat;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.CustomDefaultPreference.CustomDefaultPreferenceDialogFragmentCompat.CustomPreferenceValidator;
import org.thoughtcrime.securesms.util.TextSecurePreferences;

View File

@@ -1,7 +1,6 @@
package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.EditText;
@@ -9,10 +8,8 @@ import androidx.annotation.AttrRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.ThemeUtil;
/**
* Custom styled search view that we can insert into ActionBar menus
@@ -30,6 +27,6 @@ public class DarkSearchView extends androidx.appcompat.widget.SearchView {
super(context, attrs, defStyleAttr);
EditText searchText = findViewById(androidx.appcompat.R.id.search_src_text);
searchText.setTextColor(ThemeUtil.getThemedColor(context, R.attr.conversation_subtitle_color));
searchText.setTextColor(ContextCompat.getColor(context, R.color.signal_text_toolbar_subtitle));
}
}

View File

@@ -2,22 +2,16 @@ package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import org.thoughtcrime.securesms.R;
import pl.tajchert.sample.DotsTextView;
public class DeliveryStatusView extends FrameLayout {
private static final String TAG = DeliveryStatusView.class.getSimpleName();

View File

@@ -1,9 +1,10 @@
package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.util.AttributeSet;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.util.AttributeSet;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.Util;

View File

@@ -2,15 +2,14 @@ package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.graphics.Typeface;
import androidx.annotation.Nullable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.style.StyleSpan;
import android.util.AttributeSet;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
import org.thoughtcrime.securesms.recipients.Recipient;

View File

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

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