Compare commits

...

474 Commits

Author SHA1 Message Date
Alan Evans
9c8a99c79c Bump version to 4.53.2 2020-01-07 15:02:43 -05:00
Greyson Parrelli
c6b9855198 Always show view-once video remaining time. 2020-01-07 15:02:43 -05:00
Alan Evans
c142928fad Updated language translations. 2020-01-07 13:45:45 -05:00
Greyson Parrelli
fc0cfd5188 Disable multiselect actions for inapplicable message types. 2020-01-07 13:09:25 -05:00
Greyson Parrelli
d9c78e5c3e Fix toolbar overlap with cutouts in recipient preferences.
Fixes #9323
2020-01-07 12:17:41 -05:00
Greyson Parrelli
b449fceca0 Dismiss conversation search after swipe-to-reply.
Fixes #9325
2020-01-07 11:13:16 -05:00
Greyson Parrelli
f0d15c0bce Fix crash when clicking group avatars. 2020-01-07 10:51:40 -05:00
Greyson Parrelli
8f031f61ea Fix group update string when re-added to group. 2020-01-06 18:36:56 -05:00
Alan Evans
502e8559f0 Bump version to 4.53.1 2020-01-06 16:53:31 -05:00
Alan Evans
8cf6f7e936 Relocate jni libs. 2020-01-06 16:52:41 -05:00
Alan Evans
0ef01cc620 Bump version to 4.53.0 2020-01-06 11:08:30 -05:00
Alan Evans
930828ef86 Updated language translations. 2020-01-06 11:08:30 -05:00
Alan Evans
9ebe920195 Move all files to natural position. 2020-01-06 11:08:30 -05:00
Greyson Parrelli
0df36047e7 Ensure transport type gets reset in onNewIntent()
Fixes #9319
2020-01-06 11:08:27 -05:00
Greyson Parrelli
94604921f9 Fix issue with swipe-to-reply triggering incorrectly.
Fixes #9227
2020-01-06 11:08:27 -05:00
Curt Brune
284fe294ac Skip monochrome cameras when switching cameras on video calls. 2020-01-06 11:08:27 -05:00
Greyson Parrelli
ffa01d491a Do not list yourself in group membership updates. 2020-01-06 11:08:27 -05:00
Kevin T. Berstene
1d9513e743 Respect local camera aspect ratio in calls.
Fixes #8615
2020-01-06 11:08:27 -05:00
Greyson Parrelli
277c9e22f1 Show long-press-magnify in sticker preview screen. 2020-01-06 11:08:27 -05:00
Greyson Parrelli
4e7b4da941 Implement resumable downloads. 2020-01-06 11:08:27 -05:00
Greyson Parrelli
7e72c9c33b Add view-once tooltip. 2020-01-06 11:08:27 -05:00
Greyson Parrelli
e0e2c3a3f5 Fix some UI bugs in view-once sending. 2020-01-06 11:08:27 -05:00
Greyson Parrelli
3b5e444e76 Enable view-once send support. 2020-01-06 11:08:27 -05:00
Alan Evans
02006e3ff5 Update copyright year. 2020-01-06 11:08:27 -05:00
Greyson Parrelli
8083596f19 Use FitCenter sizing for stickers. 2020-01-06 11:08:27 -05:00
Greyson Parrelli
6551689a0c Increase the size of stickers in the conversation. 2020-01-06 11:08:27 -05:00
Greyson Parrelli
3fbf21a34e Don't crash on packs missing metadata. 2020-01-06 11:08:27 -05:00
Alan Evans
b598431237 Separate message decryption from message processing. 2020-01-06 11:08:27 -05:00
Greyson Parrelli
3b5d9a2cae Consider groups 'unknown' if they have no title, avatar, or members. 2020-01-06 11:08:27 -05:00
Alex Hart
3bd8aa8a86 Apply MessageStyle and fix chronology issues. 2020-01-06 11:08:27 -05:00
Greyson Parrelli
fe5fca8eaf Sync thread order and archive status with linked devices. 2020-01-06 11:08:27 -05:00
Greyson Parrelli
848101a783 Refactor AvatarImageView#setAvatarClickHandler.
This triggered a call to Recipient#isGroup when rendering a view, which
itself could trigger a DB read. This delays the call to #isGroup to
lower the possibility of doing DB reads on the main thread.
2019-12-19 18:06:29 -05:00
Alex Hart
d7c350f987 Fix in-call proximity lock for wireless, speaker, and bluetooth. 2019-12-19 18:06:29 -05:00
Curt Brune
4c526f0b3c Update ringrtc to 0.3.0 2019-12-19 18:06:29 -05:00
Greyson Parrelli
876ffb5b13 Bump version to 4.52.4 2019-12-19 18:00:56 -05:00
Greyson Parrelli
0b14cf3d6a Show sticker install tooltips less often. 2019-12-19 17:59:42 -05:00
Greyson Parrelli
c2044b36b1 Bump version to 4.52.3 2019-12-18 20:58:07 -05:00
Greyson Parrelli
f970b4acfa Revert "Remove the Pixel 4 from the CameraX blacklist."
This reverts commit 1f5a597d50.
2019-12-18 20:55:03 -05:00
Greyson Parrelli
e69c0af613 Bump version to 4.52.2 2019-12-18 19:56:16 -05:00
Greyson Parrelli
42e2dd8b30 Updated language translations. 2019-12-18 18:04:42 -05:00
Greyson Parrelli
4fd6e7b033 Fix issue with stickers flickering on send. 2019-12-18 16:45:07 -05:00
Greyson Parrelli
3580816eac Bump version to 4.52.1 2019-12-18 00:50:02 -05:00
Greyson Parrelli
f1c2e5f194 Updated language translations. 2019-12-18 00:49:36 -05:00
Greyson Parrelli
b6d59f1d46 Fix sticker manager text wrapping issues. 2019-12-17 22:26:09 -05:00
Greyson Parrelli
a3521681e7 Bump version to 4.52.0 2019-12-17 15:38:12 -05:00
Alan Evans
ca10e1136c Updated language translations. 2019-12-17 15:37:11 -05:00
Greyson Parrelli
282fb2af0e Fix tinting issues on API 21. 2019-12-17 14:36:54 -05:00
Greyson Parrelli
1f5a597d50 Remove the Pixel 4 from the CameraX blacklist. 2019-12-17 14:36:54 -05:00
Greyson Parrelli
a32666817c Remove old image editor stickers. 2019-12-17 14:36:54 -05:00
Greyson Parrelli
b9bd3f2b4c Launch stickers. 2019-12-17 14:36:54 -05:00
Alex Hart
4173efbe5a Fix NPE on call initalization 2019-12-16 11:01:32 -04:00
yate
8121c8bd41 Remove blank MMS config overrides.
Some SIM cards include blank values for `uaProfUrl` and `userAgent`.

Passing in these blank values along with the overrides causes a 412 precondition error when downloading MMS from ATT&T.

If these values happen to be blank, then they should be removed completely from the overrides, allowing the request to use the default `uaProfUrl` and `userAgent` for the system.

Fixes #9173
2019-12-14 11:29:46 -05:00
Greyson Parrelli
6ca8218d55 Bump version to 4.51.6 2019-12-06 11:58:12 -05:00
Greyson Parrelli
653afbdd46 Updated language translations. 2019-12-06 11:57:33 -05:00
Alex Hart
4453d1752f Fix reactions scrubber positioning on vertically split multiscreen. 2019-12-06 11:43:51 -05:00
Alan Evans
5782c8a58b Make media overview view pager scrollable for long translations. 2019-12-06 11:43:51 -05:00
Greyson Parrelli
3e041befc8 Bump version to 4.51.5 2019-12-06 01:14:24 -05:00
Greyson Parrelli
6d3847c26f Updated language translations. 2019-12-06 01:10:47 -05:00
Alex Hart
4bdfc37bc1 Fix swipe to reply clobbering long press events. 2019-12-06 01:00:39 -05:00
Alan Evans
28afe0d829 Fix first media overview item selected text. 2019-12-06 01:00:39 -05:00
Greyson Parrelli
04dddd3378 Bump version to 4.51.4 2019-12-05 19:15:10 -05:00
Greyson Parrelli
23a14583fe Updated language translations. 2019-12-05 19:14:48 -05:00
Greyson Parrelli
19c83de510 Fix possible performance issues with reactions query. 2019-12-05 19:10:37 -05:00
Greyson Parrelli
e94d4b64cf Bump version to 4.51.3 2019-12-05 12:21:12 -05:00
Greyson Parrelli
7380c99f3a Updated language translations. 2019-12-05 12:20:28 -05:00
Greyson Parrelli
2961a372c3 Avoid unneccessary recipient refreshes. 2019-12-05 12:20:28 -05:00
Greyson Parrelli
5e2a4fb058 Put safeguards around Recipient creation in the IdentityStore. 2019-12-05 12:20:28 -05:00
Greyson Parrelli
a16242b9f8 Fix issues with RecipientDatabase#update(). 2019-12-05 12:20:28 -05:00
Alan Evans
acfba9ac96 Show total file size of selected items when appropriate. 2019-12-05 12:20:28 -05:00
Alan Evans
006343460e Fix long press on image thumbnail in detail view.
Allow long press to select inside select mode.
2019-12-05 12:20:28 -05:00
Alex Hart
1cc8634cc7 Display reactions in ImageView instead of TextView on message bubbles. 2019-12-05 12:20:27 -05:00
Greyson Parrelli
9f8a110428 Bump version to 4.51.2 2019-12-05 02:59:42 -05:00
Greyson Parrelli
07b4279d0b Updated language translations. 2019-12-05 02:59:42 -05:00
Greyson Parrelli
6a33b231e3 Add a FrameRateTracker to log frame drops. 2019-12-05 02:59:42 -05:00
Greyson Parrelli
b38d02061d Improve logging in RetrieveProfileJob. 2019-12-05 02:59:42 -05:00
Greyson Parrelli
f832a36a5e Prevent possible UUID-only recipient creations. 2019-12-05 02:59:42 -05:00
Alan Evans
911ca7c29d Improve storage management detail view descriptions. 2019-12-05 02:59:42 -05:00
Greyson Parrelli
544b75a2a7 Bump version to 4.51.2 2019-12-04 15:30:30 -05:00
Greyson Parrelli
56e8d4fb06 Updated language translations. 2019-12-04 15:28:45 -05:00
Greyson Parrelli
36a2278aef Add sanity checks for phone number during link process. 2019-12-04 15:28:45 -05:00
Alex Hart
0c785b85b8 Fix video icon issue. 2019-12-04 15:28:45 -05:00
Alan Evans
a0ecba147e Use decimal digit groups in file size pretty printing. 2019-12-04 15:28:45 -05:00
Alan Evans
977591ac82 Remove assertion error in recipient preferences. 2019-12-04 15:28:28 -05:00
Greyson Parrelli
fe1838d3fe Fix issue where unlocking would dismiss MainActivity. 2019-12-04 15:25:26 -05:00
Greyson Parrelli
ede06cf97d Remove unnecessary directory refreshes. 2019-12-04 15:25:26 -05:00
Greyson Parrelli
93deee6824 Attempt to fix crash in ClassicOpenHelper.
These users must have > 1.5-year-old installs that haven't been updated,
but it's still a top crash for whatever reason, so gotta try to fix it.
2019-12-04 15:25:26 -05:00
Greyson Parrelli
db19077834 Fix crash when receiving a PreKey message in a new session.
We don't allow creating recipients with only a UUID at the moment
(for good reason), but the way the decrypt method was written, it
was possible to do so. Until we have CDS, we should prefer the phone
number in scenarios like these.
2019-12-04 15:25:26 -05:00
Alex Hart
6f91f62db2 Fix InviteActivity sendSmsMessage type error. 2019-12-04 15:25:26 -05:00
Greyson Parrelli
1fc63b7597 Fix crash in conversation search. 2019-12-04 15:25:26 -05:00
Alex Hart
a079e479ec Skip call dialog if signal call is already active. 2019-12-04 15:25:26 -05:00
Alex Hart
e90705b459 Add correct archive icon to light theme. 2019-12-04 15:25:26 -05:00
Alex Hart
244db437cb Fix reaction display issues. 2019-12-04 15:25:25 -05:00
Alan Evans
6558eae032 Fix audio color on light theme. 2019-12-04 09:10:48 -05:00
Greyson Parrelli
88b54a262b Bump version to 4.51.0 2019-12-04 00:17:03 -05:00
Alan Evans
4fa8b8a4bd Updated language translations. 2019-12-04 00:08:01 -05:00
Greyson Parrelli
cc0ced9a81 Add internal pre-alpha support for storage service. 2019-12-04 00:08:01 -05:00
Alan Evans
52447f5e97 Add storage management features. 2019-12-04 00:07:49 -05:00
Alex Hart
bceb69b284 Add internal pre-alpha support for receiving reactions. 2019-12-04 00:07:49 -05:00
Alex Hart
a8d826020d Implement new video call experience. 2019-12-04 00:07:49 -05:00
Alan Evans
2ada7f87f2 Update lib phone number. 2019-12-04 00:07:49 -05:00
Alan Evans
7f8ca58762 Add internal pre-alpha support for Registration Lock v2. 2019-12-04 00:07:49 -05:00
Greyson Parrelli
058c25808b Clean up website auto-update APKs.
I think previously we thought that because we always used the same
filename, that we were just overwring the same file repeatedly. However,
DownloadManager will actually append numbers to a filename instead of
overwriting, so we were generating a ton of files.

Now we just clear out any previous files before downloading a new one.

Related to #9033
2019-12-04 00:07:49 -05:00
Greyson Parrelli
c1e6b6b086 Add better Loader performance logs. 2019-12-04 00:07:49 -05:00
Greyson Parrelli
b0a6bb79f6 Fix issue with setting Note to Self color.
Fixes #9235
2019-12-04 00:07:49 -05:00
Greyson Parrelli
de52bf50a2 Improve image and sticker notifications. 2019-12-04 00:07:49 -05:00
Greyson Parrelli
207dd23c86 Fix performance issue with large number of notifications.
Constructing the notification would call KeyCachingService#isLocked()
many times in a loop. This call is slow, because when the device isn't
locked, it would construct the master secret each time, which can take
50+ ms. Do that twice in a loop a hundred times, and it adds up.

This simplified #isLocked to avoid the unnecessary master secret
generation.
2019-12-04 00:07:49 -05:00
Alex Hart
7e0de29dd7 Add notification policy permission and runtime check.
Fixes #9217
2019-12-04 00:07:49 -05:00
Greyson Parrelli
eaa8f1ee8f Ignore expiration updates from groups you've left. 2019-12-04 00:07:49 -05:00
Alex Hart
fb494c1151 Implement new invite screen. 2019-12-04 00:07:49 -05:00
Greyson Parrelli
49ecd9ef5d Added additional logging in RetrieveProfileJob. 2019-12-04 00:07:49 -05:00
Greyson Parrelli
8772214fd4 Increase number of log files to 7. 2019-12-04 00:07:49 -05:00
Greyson Parrelli
5b74d0cbeb Improve activity lifecycle logging. 2019-12-04 00:07:49 -05:00
Greyson Parrelli
1e7c93007d Convert the conversation list into a real fragment.
It was a fragment before, but it's functionality was inappropriately
split between the various layers.

This also sets us up better to do tablet stuff in the future, if we
choose to do that.
2019-12-04 00:07:49 -05:00
Greyson Parrelli
608815a69b Add internal pre-alpha support for usernames. 2019-12-04 00:07:42 -05:00
Greyson Parrelli
fb49efa34d Add internal pre-alpha libsignal support for reactions. 2019-12-04 00:07:13 -05:00
Android Team
b20e8616ec Move libsignal-service-java into this repo.
libsignal-service-java repo commit: 1a01c22636
2019-12-04 00:07:13 -05:00
Alan Evans
acf78b6b63 Make new top level gradle file, make app dir and move build.gradle. 2019-12-04 00:07:13 -05:00
Alex Hart
d68fe928b8 Fix nav bar contrast on sticker preview. 2019-12-04 00:07:13 -05:00
Alex Hart
db4d561d9e Fix nav bar color on shared contacts edit screen. 2019-12-04 00:07:07 -05:00
Alex Hart
6933ca50a7 Implement new Message Request UI. 2019-12-04 00:07:07 -05:00
Greyson Parrelli
88c0e6f8ab Fail a job when you can't instantiate it.
This will still crash, but prevent apps from getting into crash loops
when we have bad data in a job.
2019-11-25 11:32:16 -05:00
Greyson Parrelli
6cd4728e3c Update job serialized data after retry. 2019-11-25 11:32:16 -05:00
Greyson Parrelli
97cc82837c Don't backup the JobsDatabase. 2019-11-25 11:32:16 -05:00
Greyson Parrelli
5f0b0e8495 Bump version to 4.50.6 2019-11-25 11:32:07 -05:00
Greyson Parrelli
c837d590ab Removed RefreshUnidentifiedDeliveryAvailabilityJob.
It's been long enough -- it's no longer necessary to check.

Also, the service is going to start returning certs no matter what, so
at this point it's just an unnecessary network call.
2019-11-25 11:32:06 -05:00
Greyson Parrelli
6108a32631 Prevent reading UUIDs from external contacts. 2019-11-25 11:29:58 -05:00
Greyson Parrelli
6d78e1760d Fix possible crash in very old database migration.
The NumberMigrator constructor is crashing. One possibility is that this
migration is running before the user registered, in which case they
wouldn't have a number. Wrapped the parts that don't need to run in this
situation in an `if` block.
2019-11-25 11:29:58 -05:00
Greyson Parrelli
c7b7242eff Fix issues with blocking and MMS groups.
Fixes #9218.

Note that this removes MMS group blocking for now, just because it never
really worked, and I don't want to hotfix in a feature.
2019-11-25 11:29:19 -05:00
Greyson Parrelli
77c687efcf Bump version to 4.50.5 2019-11-21 13:28:23 -05:00
Greyson Parrelli
274af2f010 Ensure group message is being sent to a group. 2019-11-21 13:28:00 -05:00
Greyson Parrelli
6cd5100530 Ensure Recipient.self() is available. 2019-11-21 13:24:54 -05:00
Alan Evans
115a408b0b Bump version to 4.50.4 2019-11-18 09:36:14 -05:00
Alan Evans
d983016137 Updated language translations. 2019-11-18 09:33:53 -05:00
Greyson Parrelli
a8309b6b2b Fix attachment sizes during backup exports. 2019-11-18 09:19:11 -05:00
Alan Evans
e241589c92 Bump version to 4.50.3 2019-11-15 15:43:47 -05:00
Alan Evans
dcb6240a6a Updated language translations. 2019-11-15 15:39:39 -05:00
Alex Hart
599bb5ab0f Update insights copy and queries. 2019-11-15 16:33:54 -04:00
Alan Evans
739fe584c6 Bump version to 4.50.2 2019-11-14 14:49:48 -05:00
Alan Evans
920d1c6207 Updated language translations. 2019-11-14 14:49:48 -05:00
Greyson Parrelli
c1d3d26a15 Removed unnecessary subtext in Insights. 2019-11-14 14:49:48 -05:00
theBoatman
e3b66dc7e8 Fixing RealtimeSleepTimer to work in concurrent threads. 2019-11-14 13:56:12 -05:00
Alan Evans
dfa08d1356 In dark mode, use a dark theme base for RegistrationLockDialog and RationaleDialog.
Fixes #8995
Closes #9077
2019-11-14 13:51:01 -05:00
Curt Brune
6da734c2f9 Update ringrtc to 0.2.0 2019-11-13 14:05:22 -08:00
Alan Evans
a9f3141a77 Create android.yml running qa task. 2019-11-13 15:49:22 -05:00
Alan Evans
ee267d4702 Bump version to 4.50.1 2019-11-13 14:40:04 -05:00
Alan Evans
c39174ed8a Updated language translations. 2019-11-13 14:40:04 -05:00
Greyson Parrelli
9c872b6da6 Fix issue where SMS groups showing up as 'Unnamed Group'. 2019-11-13 11:37:49 -05:00
Greyson Parrelli
2924a09936 Don't run UuidMigration if not registered. 2019-11-13 11:37:49 -05:00
Greyson Parrelli
b9da012cc4 Fix media send issues on Android 4.4.
Before lollipop, Android would ignore activity results for activities
launched with singleTask. So I switched to singleTop, since that should
still solve the problem of double-activity-opens without running into
this issue.

Fixes #9149
2019-11-13 11:37:49 -05:00
Alan Evans
8626d41787 I18N for "Unlock Signal". 2019-11-13 11:37:49 -05:00
Alex Hart
c58705722a Fix Insights Adapter item text clashing. 2019-11-13 11:37:49 -05:00
Greyson Parrelli
c702ff676a Support additional sync behavior for linked devices. 2019-11-13 11:37:49 -05:00
Alan Evans
995569dd50 Bump version to 4.50.0 2019-11-12 10:55:41 -05:00
Greyson Parrelli
a0dfd42527 Fix possible context crash. 2019-11-12 10:55:41 -05:00
Alex Hart
a7dd78cce6 Implement in-app insights. 2019-11-12 10:55:41 -05:00
Greyson Parrelli
e2e9cd40b3 Blacklist additional phone models from the new camera. 2019-11-11 18:13:34 -05:00
Alan Evans
e4fc6f41b8 Schedule first backup after restore for 24hrs time. 2019-11-11 13:00:01 -05:00
Alan Evans
778b2a0d27 Remove old strings file. 2019-11-10 09:23:44 -05:00
Alan Evans
64cd15ca0b Make AlbumThumbnailView_plus non-translatable. 2019-11-10 09:23:43 -05:00
Alan Evans
1e46c3c0ba Make app_name non-translatable. 2019-11-10 09:23:43 -05:00
Alan Evans
91772b4e11 Exclude non-translatable strings.
Lint exclude ExtraTranslation.
2019-11-10 09:23:42 -05:00
Alan Evans
af5c7cb7ca Added dotted lines to time icons. 2019-11-09 07:45:53 -05:00
Alan Evans
e760474fa9 Clear unauthorized flag on connect. 2019-11-09 07:01:08 -05:00
Greyson Parrelli
28bb88e347 Lower max number of JobScheduler IDs.
Some devices can only handle 25 job IDs, so I lowered it to 20.
2019-11-09 07:01:08 -05:00
Curt Brune
17a1fe97ca Send hangup message when terminating on call errors.
When errors occur during a call, attempt to send the remote peer a
hangup message before terminating the call.  This allows the remote
peer to shutdown their side of the call in a timely manner.
2019-11-09 07:01:08 -05:00
Alan Evans
7348237862 Lint.
- baseline update.
- eradicate ButtonOrder.
- eradicate VectorRaster.
- eradicate HardcodedText.
2019-11-09 07:01:08 -05:00
Alex Hart
4e66db5dc1 Fix timer disabled icon. 2019-11-09 07:01:08 -05:00
Alex Hart
ffa6c9acd1 Utilize icon_tint color filter for UpdateItem icons. 2019-11-09 07:01:08 -05:00
Greyson Parrelli
b3e66a9259 Prevent creation of UUID-only recipients. 2019-11-09 07:01:08 -05:00
Alan Evans
5c0cf8c1f0 English staging app name. 2019-11-09 07:01:08 -05:00
Alex Hart
89c716fca4 Fix layout gravity on recv long message footer. 2019-11-09 07:01:08 -05:00
Alan Evans
aae9830dfa Use lib-signal-servivce 2.15.1 2019-11-09 07:01:08 -05:00
Alan Evans
48c72697c1 Add protobuf lite exception for proguard. 2019-11-09 07:01:08 -05:00
Greyson Parrelli
aac7e9ea53 Fix issue with ShareActivity contact display. 2019-11-09 07:01:08 -05:00
Alan Evans
a1b10b3222 Update to protobuf 3.10 lite.
Update fingerprint logic.
Update for additional validation around SignalServiceAddresses.

Co-authored-by: Greyson Parrelli <greyson@signal.org>
2019-11-09 07:01:08 -05:00
Curt Brune
2ab8db33e3 Update ringrtc to 0.1.9 2019-11-09 07:01:08 -05:00
Curt Brune
2b1386232f Implement logging interface for ringrtc-0.1.8
Implement the org.signal.ringrtc.Log.Logger interface, using
org.thoughtcrime.securesms.logging.Log as the underlying logger.

This allows ringrtc to log in the same way as the rest of the
application.
2019-11-09 07:01:07 -05:00
Alex Hart
7bb1caa22e Remove unused pictures that were captured outside of the in-app camera. 2019-11-09 07:01:07 -05:00
Alex Hart
72c14b8651 Apply new Keyboard and Dial Pad icons. 2019-11-09 07:01:07 -05:00
Alex Hart
f85c3bb1e6 Add feature flag to new Profile display. 2019-11-09 07:01:07 -05:00
Alan Evans
d8714fe3b4 Delegate to library Base64. 2019-11-09 07:01:07 -05:00
Alex Hart
c54c1907b6 Fix nav bar colors on reg and call screen. 2019-11-09 07:01:07 -05:00
Greyson Parrelli
55257155dd Handle ProtocolInvalidMessageExceptions with no sender. 2019-11-09 07:01:07 -05:00
alex-signal
55a8bd86de Consolidate profile display labels. 2019-11-09 07:01:07 -05:00
Greyson Parrelli
c60909272b UUID migration. 2019-11-09 07:01:07 -05:00
Greyson Parrelli
3dcc2d8171 Moved DirectoryHelper. 2019-11-09 07:01:07 -05:00
Greyson Parrelli
0ccbb22e4c Unsubscribe from old recipient observers in ConversationActivity. 2019-11-09 07:01:07 -05:00
Greyson Parrelli
0ffa10eaea Bump version to 4.49.18 2019-11-08 20:27:14 -05:00
Alan Evans
9824073023 Keep line numbers within R8. 2019-11-08 16:17:32 -05:00
Alan Evans
d2adc11a2d New languages.
bn,bs,ms,mr,ta,ur
2019-11-08 16:17:32 -05:00
Alan Evans
4d0b870c88 Updated language translations. 2019-11-08 16:17:32 -05:00
Alan Evans
840997cb7d Translate tasks. 2019-11-08 11:41:38 -05:00
Alex Hart
e4406621ed Fix lint issues. 2019-11-08 11:41:38 -05:00
Greyson Parrelli
7f96ee0b62 Clear DATA_HASH column. 2019-11-08 11:30:48 -05:00
Alan Evans
17f850b31a Ensure that we can still navigate when we get a response from server. 2019-11-08 11:19:57 -05:00
Alan Evans
5d87ad0301 Ignore period in phone number entry.
Fixes #9168
2019-11-08 11:19:32 -05:00
Greyson Parrelli
a33eeed6d3 Bump version to 4.49.17 2019-11-07 16:18:27 -05:00
Alex Hart
554ce29337 Adjust Typing Indicator margin in groups. 2019-11-07 16:03:13 -05:00
Alex Hart
6054d0b36f Nullify Data Hash when Data is Nullified 2019-11-07 16:02:56 -05:00
Greyson Parrelli
8ba15cf3b4 Bump version to 4.49.16 2019-11-06 16:42:16 -05:00
Greyson Parrelli
b15e5b4867 Fix potential invalid context crash. 2019-11-06 16:38:28 -05:00
Greyson Parrelli
544511905a Fix issue where deduped media might not be kept in sync. 2019-11-06 16:37:25 -05:00
Greyson Parrelli
02e3f511bd Bump version to 4.49.15 2019-11-04 11:30:08 -05:00
Alex Hart
0539b071e7 Fix message info icon inflation error on API 19 devices.
Fixes #9148
2019-11-04 11:29:31 -05:00
Greyson Parrelli
36e400650c Fix backup restore issue.
Fixes #9133
2019-11-04 11:21:11 -05:00
Greyson Parrelli
d8930daf4b Bump version to 4.49.14 2019-11-01 17:23:52 -04:00
Greyson Parrelli
17b5816d5b Skip corrupt attachments during backup restore.
Instead of aborting the entire backup restore.

Related to #8355
2019-11-01 17:11:10 -04:00
Curt Brune
e574c81ea2 Update ringrtc to 0.1.7.2 2019-11-01 12:26:00 -07:00
Greyson Parrelli
6799a2f841 Bump version to 4.49.13 2019-10-29 16:10:09 -04:00
Curt Brune
61fb20f412 Update ringrtc to v0.1.7 2019-10-29 12:46:01 -07:00
Alan Evans
47f648e7bc Correct text on registration lock fragment. 2019-10-29 13:47:14 -04:00
Alan Evans
064c0ddb82 Manually restrict to 30 digits to allow pasting containing any number of spaces. 2019-10-29 09:59:53 -04:00
Greyson Parrelli
b42c42007d Bump version to 4.49.12 2019-10-28 19:48:07 -04:00
Greyson Parrelli
807cdfce2e Increase backup passphrase input length to 35.
The way pasting works, it could prevent you from pasting in text if you
included the spaces in between number chunks.
2019-10-28 19:47:05 -04:00
Greyson Parrelli
43dc3aeebd Fix 'direct share' icon rendering issue.
Fixes #9138
2019-10-28 16:51:06 -04:00
Greyson Parrelli
0369c5ee16 Make avatars larger in conversations. 2019-10-28 16:46:21 -04:00
Greyson Parrelli
3df2390fe4 Bump version to 4.49.11 2019-10-28 12:28:58 -04:00
Greyson Parrelli
9ec4a7af0f Update max video duration for MMS. 2019-10-28 12:09:54 -04:00
Alex Hart
70636fb4a7 Blacklist Pixel4 from CameraX (#319)
* Blacklist Pixel4 from CameraX

* Create isSupported method
2019-10-28 13:07:28 -03:00
Alex Hart
3c4efdd8f9 Apply proper color when action mode destroyed 2019-10-28 12:00:59 -04:00
Greyson Parrelli
80deb301e5 Bump version to 4.49.10 2019-10-25 14:00:33 -07:00
Greyson Parrelli
5eabfdc34c Fix crash if you leave during log generation. 2019-10-25 14:00:33 -07:00
Greyson Parrelli
5e96832666 Disable video capture for legacy camera devices. 2019-10-25 13:54:38 -07:00
Alan Evans
1ccce24cf8 Fix drawable crash on API 19. 2019-10-25 15:33:34 -04:00
Greyson Parrelli
d59e4f2da7 Bump version to 4.49.9 2019-10-24 14:20:09 -07:00
Greyson Parrelli
a254c1a7b2 Updated language translations. 2019-10-24 14:17:19 -07:00
Alex Hart
82cc610938 Apply themed context to SingleRecipientNotificationBuilder 2019-10-24 17:59:34 -03:00
Greyson Parrelli
becf7c40e8 Bump version to 4.49.8 2019-10-23 23:45:13 -07:00
Greyson Parrelli
ed21c3ca03 Improve send button in media send flow.
Fixes #8988
2019-10-23 23:45:13 -07:00
Greyson Parrelli
631005e565 CameraX cleanup. 2019-10-23 23:45:13 -07:00
Greyson Parrelli
b57fab8c75 Make MediaSendActivity singleTask. 2019-10-23 23:45:13 -07:00
Greyson Parrelli
4260a8436b Fix possible de-duping issues.
- Clean bad hashes from earlier release.
- Fix file equality comparison.
- Given our new de-duping, we don't want to run into a situation where two
simultaneous compressions could be happening on the same image.
2019-10-23 23:45:13 -07:00
Greyson Parrelli
23d478191f Don't render 'null' contact labels. 2019-10-23 23:45:13 -07:00
Greyson Parrelli
d075a33d4e Fix issue where video controls may be missing.
Fixes #9121
2019-10-23 23:45:13 -07:00
Greyson Parrelli
7507dadbe7 Bump version to 4.49.7 2019-10-22 14:17:24 -04:00
Greyson Parrelli
bfd0363390 Fix potential tooltip crash. 2019-10-22 14:17:01 -04:00
Greyson Parrelli
cfb22825f4 Fix recent conversation query. 2019-10-22 13:49:31 -04:00
Greyson Parrelli
d37fafbfe7 Bump version to 4.49.6 2019-10-22 13:02:26 -04:00
Greyson Parrelli
2dc2eb5835 Updated language translations. 2019-10-22 13:02:26 -04:00
Greyson Parrelli
019d036f69 Fix soft nav color in conversation list.
Going in and out of multi-select mode would screw it up.

This fixes it by setting the flags correctly instead of blasting them
all away.
2019-10-22 13:02:26 -04:00
Greyson Parrelli
f1ca5fc8e2 Exclude inactive groups from search results where appropriate.
Fixes #9091
Fixes #9080
2019-10-22 12:41:20 -04:00
Greyson Parrelli
9089fc4001 Fix potential display issues in Message Details screen. 2019-10-22 11:00:03 -04:00
Greyson Parrelli
b281b817ba Add additional logging around attachment upload/deletion. 2019-10-22 10:52:55 -04:00
Greyson Parrelli
cee6736656 Fix flickering 'about' section in group recipient preferences.
Gotta disable those pesky layout animations.

Fixes #9092
2019-10-22 10:30:11 -04:00
Greyson Parrelli
350ca059b9 Pick camera resolution based on screen resolution. 2019-10-22 10:16:14 -04:00
Greyson Parrelli
a7cc5bdc5e Ensure keyboard is hidden when going to the gallery.
Fixes #9120
2019-10-22 09:50:01 -04:00
Greyson Parrelli
2893dfff60 Bump version to 4.49.5 2019-10-21 20:05:31 -04:00
Greyson Parrelli
1c14f06734 Updated language translations. 2019-10-21 20:04:20 -04:00
Greyson Parrelli
ff053437e3 Fix issue where album rail wasn't immediately shown.
Fixes #9111
2019-10-21 20:04:20 -04:00
Alex Hart
03dc220cea Fix crash related to unsupported camera mode.
Fixes #9106
2019-10-21 19:32:19 -04:00
Greyson Parrelli
097f97b5e4 Add system to allow skipping attachment compression. 2019-10-21 19:32:19 -04:00
Alex Hart
95d3db3260 Add ic_message webp files 2019-10-21 15:30:20 -03:00
Greyson Parrelli
0485ae603b Set targetResolution to something reasonable for camera capture. 2019-10-21 10:58:07 -04:00
Alex Hart
2f93da6f1a Fix wrong icon color in expiry footer 2019-10-21 11:50:32 -03:00
Alex Hart
78f3e28974 Fix progress wheel color in share screen 2019-10-21 10:53:18 -03:00
Alex Hart
fecd8300c3 Swap ValueAnimator with version from NineOldAndroids 2019-10-21 10:51:04 -03:00
Alex Hart
262f90dbe7 Add new info icon to message details view 2019-10-21 10:09:54 -03:00
Alex Hart
ed271c6f3e Fix longmessage and shared contact footer alignment 2019-10-21 10:00:28 -03:00
Greyson Parrelli
3fa5843c93 Bump version to 4.49.4 2019-10-21 01:13:19 -04:00
Greyson Parrelli
7f544cb3e5 Updated language translations. 2019-10-21 01:12:51 -04:00
Greyson Parrelli
9f4d40a364 Revert "Prevent compression of images without EXIF data."
This reverts commit 8449d75684.
2019-10-21 01:00:31 -04:00
Greyson Parrelli
09f0c5b63f Fix bug in manual conversation search query submission.
Fixes #9115
2019-10-21 00:49:06 -04:00
Greyson Parrelli
53e0dc5dee Potential MMS download fix for some users.
Special thanks to @mdaniel

Fixes #8571
2019-10-21 00:36:54 -04:00
Greyson Parrelli
8b06051e7c Fix blurhash being visible on transparent images. 2019-10-21 00:21:53 -04:00
Greyson Parrelli
660ec88202 Fix data deduping issues.
Fixes #9109
2019-10-21 00:21:48 -04:00
Greyson Parrelli
b9057a1c11 Use fallback images for Giphy results. 2019-10-20 01:13:02 -04:00
Greyson Parrelli
1f85b1f3d2 Bump version to 4.49.3 2019-10-19 12:37:00 -04:00
Greyson Parrelli
71f78f03f4 Updated language translations. 2019-10-19 12:34:30 -04:00
Greyson Parrelli
4b3d129097 Cleanup some possible bad RecipientIds in the MMS table. 2019-10-19 12:31:06 -04:00
Greyson Parrelli
daeb823399 Fix CameraX crash. 2019-10-19 12:25:40 -04:00
Greyson Parrelli
c7f76c5d1c Add a util to safely set a MediaMetadataRetriever data source. 2019-10-19 12:23:23 -04:00
Greyson Parrelli
9ba1391a1e Fix issue with non-contact avatar colors not updating. 2019-10-19 12:15:14 -04:00
Greyson Parrelli
5d137465e8 Bump version to 4.49.2 2019-10-18 18:46:07 -04:00
Greyson Parrelli
78cbb3c073 Updated language translations. 2019-10-18 18:45:43 -04:00
Greyson Parrelli
097d95428a Fix conversation list toolbar styling. 2019-10-18 17:34:01 -04:00
Greyson Parrelli
2cfb6ede7f Increase record button size. 2019-10-18 17:34:01 -04:00
Greyson Parrelli
695663a5b1 Log more data about video capture support. 2019-10-18 17:34:01 -04:00
Greyson Parrelli
a2204c8370 Update video recording tooltip text. 2019-10-18 17:34:01 -04:00
Alex Hart
8c4757ea02 Fix safety number theme 2019-10-18 17:34:01 -04:00
Greyson Parrelli
85821274fa Don't render null phone number labels. 2019-10-18 17:34:01 -04:00
Greyson Parrelli
a8b1ec8e52 Increase compose maxLines to 5. 2019-10-18 17:34:01 -04:00
Alex Hart
adbdaebd69 Fix invite screen theme. 2019-10-18 17:33:45 -04:00
Alex Hart
c2da4fcd7d Update CameraX to Alpha06 and bring in new View / Module code. 2019-10-18 17:36:00 -03:00
Greyson Parrelli
46ebff3659 Bump version to 4.49.1 2019-10-18 13:58:59 -04:00
Greyson Parrelli
452ccd0350 Updated language translations. 2019-10-18 13:58:35 -04:00
Alan Evans
6e6c809690 Use lighter-weight shadow view. 2019-10-18 13:51:56 -04:00
Greyson Parrelli
7b5c1904cf Update contact list divider styling. 2019-10-18 13:09:20 -04:00
Alex Hart
c0aa9d7587 Update preference divider colors 2019-10-18 13:09:20 -04:00
Alex Hart
5d03e3d516 Apply video recording permissions checks and error handling. 2019-10-18 13:09:20 -04:00
Greyson Parrelli
2bc3a4417f Fix possible crash when retrieving a video thumbnail. 2019-10-18 11:10:26 -04:00
Greyson Parrelli
59d03cbeb2 Address possible issues with AvatarMigrationJob. 2019-10-18 11:08:06 -04:00
Alex Hart
f9f9ae68f5 Fix MediaSendActivity send button metrics and positioning. 2019-10-18 10:49:54 -03:00
Alex Hart
88f2b67984 Fix crash on conversation color picker open. 2019-10-18 10:33:10 -03:00
Greyson Parrelli
44dba4bd98 Only show video tooltip if capable. 2019-10-18 09:31:01 -04:00
Alan Evans
ef585eba42 Revert "Fix invite drawable on API 21."
This reverts commit 78fbfe40736dd8c9ccafb402aa7fc6921c1d4496.

We have turned on AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) now for API19.
2019-10-18 09:15:20 -04:00
Alex Hart
42967dab13 Apply proper tinting to conversation app bar. 2019-10-18 09:55:27 -03:00
Greyson Parrelli
4f75d1a5db Bump version to 4.49.0 2019-10-17 22:45:56 -04:00
Greyson Parrelli
debacbdf58 Updated language translations. 2019-10-17 22:44:32 -04:00
Greyson Parrelli
12c4283c30 Conditionally show a toolbar shadow in the conversation list. 2019-10-17 22:23:27 -04:00
Greyson Parrelli
096c9e0ff7 Ensure videos are paused properly in MediaSendActivity. 2019-10-17 21:33:52 -04:00
Greyson Parrelli
2f23a13a6f Fix issue where video playback controls sometimes don't appear. 2019-10-17 21:33:52 -04:00
Alan Evans
bdadbaaac4 Remove larger images for link preview intro.
(I bet you thought they would be together forever).
2019-10-17 21:33:52 -04:00
Alan Evans
16f41555ba Local SMS rate limiting. 2019-10-17 21:33:52 -04:00
Greyson Parrelli
8c037456e7 Warm up LiveRecipientCache at launch. 2019-10-17 21:33:52 -04:00
Greyson Parrelli
feccee557e Include better defaults for ConversationActivity. 2019-10-17 21:33:52 -04:00
Greyson Parrelli
67f5605bc4 Block in RestStrategy until PushDecryptJobs finish. 2019-10-17 21:33:52 -04:00
Greyson Parrelli
ccb18cd46c Added JobTracker. 2019-10-17 21:33:52 -04:00
Alan Evans
5b1d91016c Fix backup sorting logic and do not delete non-backups in path. 2019-10-17 21:33:52 -04:00
Alan Evans
27ab04ab41 Add version and spread out witness information. 2019-10-17 21:33:52 -04:00
alex-signal
9432a45b39 Implement blur-hash based low resolution thumbnail previews. 2019-10-17 21:33:52 -04:00
alex-signal
9e3475ed94 Upgrade Gradle to 5.6.2 and AGP to 3.5.1 2019-10-17 21:33:52 -04:00
Alan Evans
86d088bce2 Improved registration flow. 2019-10-17 21:33:52 -04:00
alex-signal
a135e7efa2 Check DND settings before show activity or play ring or vibrate. 2019-10-17 21:33:52 -04:00
tzm
c247935f1a Fix NPE when has no contact permissions.
Fixes #9048

Co-authored-by: Alan Evans <alan@signal.org>
2019-10-17 21:33:52 -04:00
Alan Evans
31657f5c15 Gradle witness sort dependencies and move to own auto generated file. 2019-10-17 21:33:52 -04:00
Greyson Parrelli
bcecc30d33 Disallow RecipientId's of zero. 2019-10-17 21:33:52 -04:00
Greyson Parrelli
7193252d77 Fix TooltipPopup positioning. 2019-10-17 21:33:51 -04:00
Greyson Parrelli
5b682a3a3d Use our own location retriever. 2019-10-17 21:33:51 -04:00
Greyson Parrelli
6b8659a393 Move JobManager to ApplicationDependencies. 2019-10-17 21:33:51 -04:00
Alan Evans
14557d3dc1 Change default GZIP behavior on Base64.decode(String).
Remove only reference to Base64.decode(byte[]).
2019-10-17 21:33:51 -04:00
Curt Brune
03cbee0277 Add ringrtc support.
RingRTC provides Signal Messenger applications with a common interface
for video and voice calling services built on top of WebRTC.
2019-10-17 21:33:51 -04:00
alex-signal
adc0907906 Copy image to encrypted blob and delete from device immediately.
Fixes #9097
2019-10-17 21:33:51 -04:00
Alan Evans
f14a71a076 Update Lint suppressions. 2019-10-17 21:33:51 -04:00
alex-signal
12c2b53f7c Set icon to themed version via attribute.
Fixes #9054
2019-10-17 21:33:51 -04:00
alex-signal
ff60b5b731 Add in-app video recording for supported devices. 2019-10-17 21:33:51 -04:00
alex-signal
43954a176a Apply new Signal icons and color palette. 2019-10-17 21:33:51 -04:00
Alex Hart
d698d3bd6f Added support for view-once video. 2019-10-17 16:01:34 -04:00
Greyson Parrelli
50a81c0e60 Added a simple staging build config. 2019-10-17 16:01:34 -04:00
Greyson Parrelli
b0b8377a8e Migrate notification channels to recipientId's. 2019-10-17 16:01:34 -04:00
alex-signal
7d02bb8487 Store file hash to avoid data duplication. 2019-10-17 16:01:34 -04:00
alex-signal
8449d75684 Prevent compression of images without EXIF data. 2019-10-17 16:01:34 -04:00
Greyson Parrelli
b89163bb14 Migrate avatars to use recipientId filenames. 2019-10-17 16:01:34 -04:00
Greyson Parrelli
b7ce220600 Updated libsignal version to 2.13.8 2019-10-15 10:35:59 -04:00
Greyson Parrelli
948079a42e Bump version to 4.48.17 2019-10-15 10:35:15 -04:00
Greyson Parrelli
de1c6cdd0c Fix crash when MMS messages have no 'from' address. 2019-10-15 10:35:15 -04:00
Greyson Parrelli
37147fb0a5 Bump version to 4.48.16 2019-10-08 21:28:54 -07:00
Greyson Parrelli
33334f80c3 Add back proper support for unknown recipients.
Fixes #9085
2019-10-08 21:28:35 -07:00
Greyson Parrelli
36286da9bd Bump version to 4.48.15 2019-10-08 14:23:29 -07:00
Greyson Parrelli
2248acb9f2 Remove unnecessary resolves. 2019-10-08 14:23:29 -07:00
Greyson Parrelli
3632a2cc95 Hide no-name contacts from system search results. 2019-10-08 13:38:20 -07:00
Greyson Parrelli
9447ea12cb Remove concept of 'unknown' recipient. 2019-10-08 13:33:13 -07:00
Greyson Parrelli
89c2329fdf Bump version to 4.48.14 2019-10-07 16:52:36 -07:00
Greyson Parrelli
84012c7adb Fix crash in SmsMigrator. 2019-10-07 16:41:47 -07:00
Greyson Parrelli
d7395af774 Simplify recipient inserts. 2019-10-07 16:31:04 -07:00
Greyson Parrelli
be4daff0f3 Ensure recipient models are up-to-date. 2019-10-07 16:31:04 -07:00
Greyson Parrelli
c2459d0a31 Bump version to 4.48.13 2019-10-04 12:13:16 -04:00
Greyson Parrelli
5f993ed0f7 Fix threading issue in RecipientDatabase. 2019-10-04 12:07:46 -04:00
Greyson Parrelli
acea24c19c Reduce Recipient refreshes. 2019-10-04 10:52:43 -04:00
Greyson Parrelli
82b5d58d04 Fix threading issues in LiveRecipient. 2019-10-04 10:52:43 -04:00
Greyson Parrelli
af2990fa08 Bump version to 4.48.12 2019-10-03 16:08:18 -04:00
Greyson Parrelli
0fa48540e1 Fix migration of old pending SMS sends. 2019-10-03 16:07:53 -04:00
Greyson Parrelli
0f06b96832 Bump version to 4.48.11 2019-10-03 11:18:51 -04:00
Greyson Parrelli
4f423be6f9 Updated language translations. 2019-10-03 11:18:07 -04:00
Greyson Parrelli
bea21ed5ff Further recipient insertion improvements. 2019-10-03 11:17:48 -04:00
Greyson Parrelli
a9cff032f5 Bump version to 4.48.10 2019-10-02 20:44:22 -04:00
Greyson Parrelli
b2d02d4ace Add extra protections to recipient insertions. 2019-10-02 20:13:49 -04:00
Greyson Parrelli
066df77abf Revert "Use recipientId's in ContactSelectionListAdapter."
This reverts commit 89e075c56e.
2019-10-02 19:26:24 -04:00
Greyson Parrelli
b38a3e6259 Remove unnecessary recipient resolves. 2019-10-02 19:16:59 -04:00
Greyson Parrelli
d78919acf8 Bump version to 4.48.9 2019-10-02 12:36:24 -04:00
Greyson Parrelli
af96d11188 Pretty-print missing recipientId crashes. 2019-10-02 12:22:26 -04:00
Greyson Parrelli
5e1bef26ed Fix display of profile names in FTS results. 2019-10-02 12:22:26 -04:00
Greyson Parrelli
95333eccd4 Cleanup bad recipients. 2019-10-02 12:22:26 -04:00
Greyson Parrelli
89e075c56e Use recipientId's in ContactSelectionListAdapter. 2019-10-02 11:24:55 -04:00
Greyson Parrelli
d026498a8c Use recipientId's in SearchRepository. 2019-10-02 11:24:55 -04:00
Greyson Parrelli
bae381e6f8 Bump version to 4.48.8 2019-10-01 08:20:16 -04:00
Greyson Parrelli
050f7a24c9 Updated language translations. 2019-10-01 08:19:46 -04:00
Greyson Parrelli
77ad1ea729 Prevent ConversationActivity recipientId crash. 2019-10-01 08:17:25 -04:00
Greyson Parrelli
bf667c0cfc Revert "Add logging to track down ConversationActivity crash."
This reverts commit 447236ee38.
2019-10-01 08:16:57 -04:00
Greyson Parrelli
ccb8ef98b4 Bump version to 4.48.7 2019-09-30 15:19:41 -04:00
Greyson Parrelli
a1f0660339 Updated language translations. 2019-09-30 15:19:24 -04:00
Greyson Parrelli
447236ee38 Add logging to track down ConversationActivity crash. 2019-09-30 15:19:24 -04:00
Alan Evans
ebf3b0dfe1 Change versionCode for universal builds. 2019-09-30 14:16:49 -04:00
Greyson Parrelli
ee9216df8a Ensure group status is available in ConversationAdapter constructor. 2019-09-30 14:15:19 -04:00
Greyson Parrelli
3e34668232 Bump version to 4.48.6 2019-09-28 00:16:41 -04:00
Curt Brune
8f8f41f184 Localize call audio and video activation code 2019-09-28 00:16:09 -04:00
Greyson Parrelli
4f7cba8d7c Bump version to 4.48.5 2019-09-27 14:26:08 -04:00
Greyson Parrelli
00b719c783 Updated language translations. 2019-09-27 14:22:13 -04:00
Greyson Parrelli
b03eccec33 Persist the JobFactory key after job migrations. 2019-09-27 14:18:15 -04:00
Greyson Parrelli
5805539deb Revert "Potential MMS download fix for some users."
This reverts commit 1e375ec494.
2019-09-27 14:02:01 -04:00
Greyson Parrelli
1b48fd07a3 Bump version to 4.48.4 2019-09-26 18:32:28 -04:00
Greyson Parrelli
1e375ec494 Potential MMS download fix for some users.
Special thanks to @mdaniel

Fixes #8571
2019-09-26 18:32:28 -04:00
Greyson Parrelli
ee9acf2687 Show tooltip for swipe-to-reply. 2019-09-26 16:37:09 -04:00
Greyson Parrelli
1d8e85fcad Updated the feel of swipe-to-reply. 2019-09-26 16:36:52 -04:00
Greyson Parrelli
4e2afa7362 Fix some more broken JobMigrations. 2019-09-26 11:18:04 -04:00
Greyson Parrelli
d06564c7b9 Bump version to 4.48.3 2019-09-25 19:12:24 -04:00
Greyson Parrelli
ced48d0788 Fix custom notification creation. 2019-09-25 18:58:21 -04:00
Greyson Parrelli
e273593343 Fix more possible JobMigration crashes. 2019-09-25 15:19:08 -04:00
Greyson Parrelli
c5767b07a7 Initialize CameraX on a background thread.
We saw a situation where CameraX initialization could lock up when
trying to obtain system resource. We already fallback to the
Camera1Fragment when CameraX isn't initialized, so it should be safe to
do this initialization on its own thread.
2019-09-25 15:17:35 -04:00
Greyson Parrelli
709ce7e9de Bump version to 4.48.2 2019-09-25 11:37:55 -04:00
Greyson Parrelli
a8f7908ed4 Updated language translations. 2019-09-25 11:37:55 -04:00
Greyson Parrelli
8230786638 Added permissions to the debug log. 2019-09-25 11:23:23 -04:00
Greyson Parrelli
df4ecc4e32 Add blocked threads to the debug log. 2019-09-25 11:23:23 -04:00
Greyson Parrelli
5b755b9501 Crash early when using a null RecipientId. 2019-09-25 09:51:50 -04:00
Greyson Parrelli
b3c7c8db5c Fix possible crash in DirectoryRefreshJob. 2019-09-25 09:51:50 -04:00
Greyson Parrelli
a21c537428 Fix crash during JobMigration. 2019-09-25 09:51:50 -04:00
Greyson Parrelli
6d339cd023 Fix a crash when starting a call from the system contacts. 2019-09-25 09:51:50 -04:00
Alan Evans
840c493265 Fix pretty print phone numbers.
Fixes #9047
2019-09-25 09:49:26 -04:00
alex-signal
14999800e2 Fix Swipe to Reply progress reset when AnimatorDurationScale is 0.
Fixes #9051
2019-09-25 10:08:10 -03:00
Greyson Parrelli
8e332d0798 Bump version to 4.48.1 2019-09-24 12:13:27 -04:00
Greyson Parrelli
cd007a20d7 Fix possible thread visibility issue in CellConstraintObserver.
Related to #9030.
2019-09-24 12:13:27 -04:00
Greyson Parrelli
8b99af3eef Fix threading issues with LiveRecipient. 2019-09-24 12:03:33 -04:00
Greyson Parrelli
d354de806e Bump version to 4.48.0 2019-09-24 10:24:37 -04:00
alex-signal
c7ef0c06f8 Fix exif dimension edge case and handle invalid dimens better in ThumbnailView. 2019-09-24 10:11:17 -04:00
Greyson Parrelli
9d14bcb808 Enable sticker sharing. 2019-09-24 10:11:17 -04:00
alex-signal
de03706d8d Fix video thumbnail not displaying after sharing to conversation thread. 2019-09-24 10:11:17 -04:00
alex-signal
a3caabcafd Fix video forwarding thumbnail display. 2019-09-24 10:11:17 -04:00
alex-signal
faafa40122 Fix DecryptableStreamLocalUriFetcher bug for external video thumbnails.
Fix bug where external video thumbnails do not appear.
2019-09-24 10:11:17 -04:00
Greyson Parrelli
d1a6582ad7 Support independent application migration versions. 2019-09-24 10:11:17 -04:00
alex-signal
f81c0b448e Add CameraXFlashToggleView and selfie flash. 2019-09-24 10:11:17 -04:00
Greyson Parrelli
70347e754c Add a feature flag system. 2019-09-24 10:11:17 -04:00
Greyson Parrelli
a1245baf61 Don't show MMS groups in recent Signal contacts list. 2019-09-24 10:11:17 -04:00
Alex Hart
007ea43dc8 Add Swipe-To-Reply in conversations.
Swipe-To-Reply is a progress based animation that is controlled
by the ConversationItemSwipeCallback.  We use the TouchListener to
keep track of the latest down coordinates, so that we can check whether
we are over a seek bar. The SwipeAnimationHelper is responsible for
actually performing the transitions as the swipe progresses.
2019-09-24 10:11:17 -04:00
Greyson Parrelli
582028f2c2 Search contacts via the RecipientDatabase. 2019-09-24 10:11:17 -04:00
Greyson Parrelli
0e2d52026e Migrated to locally-assigned RecipientId's.
Oh boy.
2019-09-24 10:11:17 -04:00
Greyson Parrelli
233cc7ecce Bump version to 4.47.6 2019-09-16 17:00:06 -04:00
Greyson Parrelli
1baf03f51a Fix message fetching bug when app is in the foreground.
Fixes #9036
2019-09-16 16:58:51 -04:00
Greyson Parrelli
f066a9cab2 Bump version to 4.47.5 2019-09-11 18:01:50 -04:00
Curt Brune
825d1a02ab Update to WebRTC M77 2019-09-11 13:55:26 -07:00
Curt Brune
97cc8b7777 Revert "Add ringrtc support."
Revert the following commits:

"Handle busy call while in PSTN call."
Commit 23a0bb3ce0.

"Add ringrtc support."
Commit 3ac540c687.
2019-09-11 11:17:23 -07:00
Greyson Parrelli
72662b5b52 Bump version to 4.47.4 2019-09-06 13:56:17 -04:00
Greyson Parrelli
ea4e0b6d6f Updated language translations. 2019-09-06 13:56:04 -04:00
Alan Evans
6df93c0bb5 Fix potential contact search crash. 2019-09-06 13:53:26 -04:00
Curt Brune
23a0bb3ce0 Handle busy call while in PSTN call. 2019-09-06 10:20:32 -07:00
Greyson Parrelli
4cd5256267 Bump version to 4.47.3 2019-09-04 11:10:47 -04:00
Greyson Parrelli
5362e07a5c Fix crash that may happen upon first sticker install. 2019-09-04 11:09:30 -04:00
Greyson Parrelli
936bd327bd Bump version to 4.47.2 2019-09-03 15:38:34 -04:00
Greyson Parrelli
db89619a4a Updated language translations. 2019-09-03 15:38:20 -04:00
Alan Evans
b5ce7325fc Fix invite drawable on API 19. 2019-09-03 15:20:09 -04:00
Greyson Parrelli
ccaeb089ab Bump version to 4.47.1 2019-09-02 18:57:14 -04:00
Greyson Parrelli
3240ba3a55 Updated language translations. 2019-09-02 18:53:57 -04:00
Alan Evans
bb7be66efe Fix stickers in image editor.
Fixes #9012
2019-09-02 18:16:30 -04:00
Alan Evans
8814a0d949 Update invite icon. 2019-09-02 18:15:27 -04:00
Greyson Parrelli
9aa488223f Bump version to 4.47.0 2019-08-31 11:28:34 -04:00
Greyson Parrelli
30d9233365 Updated language translations. 2019-08-31 11:28:34 -04:00
Curt Brune
3ac540c687 Add ringrtc support.
RingRTC provides Signal Messenger applications with a common interface
for video and voice calling services built on top of WebRTC.
2019-08-31 07:54:47 -07:00
Alan Evans
8d561ead21 Stickers in image editor. 2019-08-30 17:45:35 -04:00
Alan Evans
15b650382e Fullscreen media preview on tap. 2019-08-30 17:31:59 -04:00
Oscar Mira
110a40592b Make E164 log scrubber redact numbers of length >= 7. 2019-08-30 08:20:21 -04:00
Alan Evans
d0ce4ff032 Lottie play pause animation. 2019-08-29 11:57:41 -04:00
Alan Evans
85c9a9050a Add an invite button in the new conversation screen. 2019-08-29 11:07:33 -04:00
Greyson Parrelli
af42d5b671 Create system for job migrations. 2019-08-29 11:07:33 -04:00
Greyson Parrelli
9580bb0a38 Renamed WorkManager migration package. 2019-08-29 11:07:33 -04:00
Greyson Parrelli
9abb167874 Bump version to 4.46.2 2019-08-28 10:27:40 -04:00
Greyson Parrelli
cd13676a21 Updated language translations. 2019-08-28 10:26:29 -04:00
Greyson Parrelli
1dd59bee36 Use raw versionCodes in web apk json.
We missed a spot when transitioning to split apk versions. It ended up
breaking the update prompt for web apks.

This will put the raw universal apk version in the json file, which
should put us back on the right track.

Fixes #8936
2019-08-28 10:26:29 -04:00
Greyson Parrelli
59bcbe592b Revert "Add ringrtc support"
This reverts commit 7f0a7b0c13.
2019-08-28 09:16:51 -04:00
Greyson Parrelli
0917e17c69 Fix bug where you couldn't reply with media.
Fixes ##8999
2019-08-27 09:40:32 -04:00
Greyson Parrelli
eb249ca69a Bump version to 4.46.1 2019-08-24 15:18:22 -04:00
Greyson Parrelli
97d1175915 Updated language translations. 2019-08-24 14:35:35 -04:00
Alan Evans
2141f1073e Ensure memory file descriptor is available. 2019-08-24 14:30:02 -04:00
Greyson Parrelli
c6287547a3 Improve video transcoding exception handling.
Previously, we'd crash if we couldn't find the attachment at runtime,
but that's not uncommon if someone deletes before sending. Now we just
fail.

Also, previously we'd fail if we couldn't create a memory file. Now we
will only fail if the attachment is >100mb (same as the other video
failures).
2019-08-24 09:27:08 -04:00
Greyson Parrelli
9257c6ddf3 Fix failure propogation in longer job chains. 2019-08-24 09:09:20 -04:00
Greyson Parrelli
480748e1aa Bump version to 4.46.0 2019-08-23 10:01:29 -04:00
Greyson Parrelli
c015687951 Updated language translations. 2019-08-23 10:01:06 -04:00
Alan Evans
1bd1e9cc65 Read optional video display dimensions.
Add RequiresApi annotations.

Fixes #8982
2019-08-22 10:15:56 -04:00
Alan Evans
c4a4374465 RTL screen animations.
RTL fix Profile name in Settings.
2019-08-22 10:15:56 -04:00
Alan Evans
90681d47f8 Fix first item sticky header. 2019-08-22 10:15:56 -04:00
Alan Evans
936be693ce Enlarge some home touch targets and add search content description. 2019-08-22 10:15:56 -04:00
Alan Evans
a32b875587 Support disabled animations for accessibility. 2019-08-22 10:15:56 -04:00
Alan Evans
4e6798e38e Fix occasional double scroll bar on fast scroller. 2019-08-22 10:15:56 -04:00
Alan Evans
6352f7baf4 Update item design in contact selection. 2019-08-22 10:15:56 -04:00
Alan Evans
aac9725adc Move shared attachment job generation code to parent class. 2019-08-22 10:15:56 -04:00
Alan Evans
900371bb30 Call answer button listens to accessibility changes. 2019-08-22 10:15:56 -04:00
Alan Evans
a58f564d1e Escape string within Full Text Search.
Fixes #8975
2019-08-22 10:15:56 -04:00
Alan Evans
942154a61f Separate compression job. 2019-08-22 10:04:23 -04:00
Curt Brune
7f0a7b0c13 Add ringrtc support
Initial commit of the RingRTC Java interface implementation.

The implementation lives in an external .aar with the package
org.signal.ringrtc.

The package provides two high level objects of interest
=======================================================

org.signal.ringrtc.CallConnection -- represents the session of a call,
very similar to WebRTC's PeerConnection.

org.signal.ringrtc.CallConnectionFactory -- creates CallConnection
objects, very similar to WebRTC's PeerConnectionFactory.

The implementation interfaces with the Android application in a few
places:
==================================================================

src/org/thoughtcrime/securesms/ApplicationContext.java -- RingRTC
library initialization at application startup.

src/org/thoughtcrime/securesms/service/WebRtcCallService.java -- Call
creation and state machine.

src/org/thoughtcrime/securesms/ringrtc -- this package implements
interface classes needed by ringrtc and a CallConnectionWrapper helper
class.

The two interfaces needed so far are:

  ringrtc/Logger.java
  ringrtc/SignalMessageRecipient.java

The logger is self-explanatory, but SignalMessageRecipient is a little
more involved.  SignalMessageRecipient encapsulates the Signal-Android
notion of "Recipient" and the mechanism for sending Signal Messages
related to audio/video calling.

The CallConnectionWrapper class is clone of the original
org.thoughtcrime.securesms.webrtc.PeerConnectionWrapper, suitably
modified to match the CallConnection interface.

This class continues to handle the Camera switching APIs, with that
portion of the code remaining unmodified from the original.

CallConnectionFactory Details
=============================

The primary public methods:

initialize() -- initialize the WebRTC library and RingRTC library.
The WebRTC initialization is lifted from the original Signal-Android
code.

createCallConnectionFactory() -- creates a CallConnectionFactory
object.  Internally it creates a WebRTC PeerConnectionFactory object
and a RingRTC CallConnectionFactory object.

dispose() -- tears down the CallConnectionFactory object, including
the internal PeerConnectionFactory and RingRTC CallConnectionFactory.

createCallConnection() -- creates a CallConnection object, connecting
that with an application controlled CallConnection.Observer object.

This function takes a CallConnection.Configuration object to link the
CallConnection object with some application provided services, like
sending Signal protocol messages.

CallConnection Details
======================

This object is a subclass of WebRTC's PeerConnection class.

The primary public methods and objects:

CallConnection.Configuration
----------------------------

Configuration object used to parameterize a call.  Notable members:

- SignalServiceMessageSender messageSender
- long callId
- org.signal.SignalMessageRecipient recipient

The 'accountManager' is used to fetch public information from the Signal
service, specifically used here to obtain the public Signal TURN
server details.

The 'callId' is a 64-bit pseudo-random number generated when the call
is initiated, used to identify the call through out its lifetime.

The "recipient' is an implementation of the
org.signal.SignalMessageRecipient interface, which encapsulates the
sending of Signal service messages to a recipient (remote peer) using
existing Signal protocol data structures.

The native library needs to be able to send Signal messages via the
service, but it does not have a native implementation to do so.
Instead the native code calls out to the client for sending Signal
messages.  To accomplish this, the client implements the
org.signal.SignalMessageRecipient interface and passes an instance of
that in a CallConnection.Configuration object.

CallConnection
--------------

dispose() -- tears down the CallConnection object, including the
internal PeerConnection and RingRTC CallConnection.

sendOffer() -- initiates a call to a remote recipient.  This is the
beginning of an outbound call.

validateResponse() -- checks an offer response recipient against the
originating call details.

handleOfferAnswer() -- handles the receipt of answer, which was a
response from an originating offer.

acceptOffer() -- accept an offer from a remote participant.  This is
the begin of an incoming call.

answerCall() -- invoked when the call is completely established and
online.

hangUp() -- hang up the connection and shut things done.  This is the
end of the call.

sendBusy() -- send the remote side an indication that the local side
is already in a call and the line is busy.

sendVideoStatus() -- send the current state of the local camera video
stream to the remote side.

CallConnection.Observer
-----------------------

Observer object, used by the RingRTC library to notify the client
application of important events and status changes.  Similar in spirit
to WebRTC's PeerConnection.Observer.

Observer callbacks come in three flavors:

- state change notifications,
- on stream notifications
- errors conditions

For state notifications, the callback contains the callId, the
recipient and a CallConnection.CallEvent type.

For streams, the callback contains the callId, the
recipient and a org.webrtc.MediaStream.

For errors, the callback contains the callId, the recipient and an
exception type.  The currently thrown exceptions include:

- UntrustedIdentityException
- UnregisteredUserException
- IOException

Signed-off-by: Curt Brune <curt@signal.org>

Updates to support ringrtc-android version 0.1.0.

* simplify logging interface

It is no longer necessary for the application to specify a Log object
as the library can log via the NDK directly.

* improve error handling and notification

In a number of places where ringrtc errors could occur, no
notification was ever sent to the user, nor was the UI cleaned up.  It
would look like the app was in hung state.

This patch updates these situations to send the WebRtcViewModel a
NETWORK_FAILURE message.

* update handleIncomingCall() for lockManager and notification

During the conversion to RingRTC, the implementation of
handleIncomingCall() missed a couple of things:

-- updating the Phone state with the lockManager
-- sending a message to the viewModel

* log the callId in various handler methods

For debugging purposes it is very handy to have the callId present in
the log during the various call handler methods.

Signed-off-by: Curt Brune <curt@signal.org>
2019-08-22 10:04:23 -04:00
Alan Evans
37bcac40bb URL encoded scrubber.
* Replace scrubber and tests.

* Improves email regex performance.
2019-08-22 10:04:23 -04:00
Greyson Parrelli
02ea99254a Reset message receiver upon REST failure.
We've been seeing a lot of socket timeouts on REST requests under
certain conditions. The issue seems to be a problem with the OkHttp
client. Through testing, I've seen that resetting the receiver and
retrying again seems to resolve most issues.
2019-08-22 10:04:23 -04:00
Greyson Parrelli
3849b46f0a Refactor ApplicationDependencies. 2019-08-22 10:04:23 -04:00
Greyson Parrelli
116bd41c63 Use EmojiTextView in the sticker preview. 2019-08-22 10:04:23 -04:00
Greyson Parrelli
457ad4c607 Added a central system for message retrieval. 2019-08-22 10:04:23 -04:00
Greyson Parrelli
d0a9bd4c6d Create a new system for application-level migrations. 2019-08-22 10:04:23 -04:00
Greyson Parrelli
d3bed549f2 Switch back to storing incoming messages in PushDatabase.
On a Pixel 3, this adds ~30-40ms of delay, but it's going to be a
requirement for upcoming migrations.
2019-08-22 10:04:23 -04:00
Alan Evans
fe1aa016b9 Refactor group operations. 2019-08-22 10:04:17 -04:00
3902 changed files with 86186 additions and 33491 deletions

17
.github/workflows/android.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
name: Android CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Build with Gradle
run: ./gradlew qa

1
.gitignore vendored
View File

@@ -1,4 +1,5 @@
.classpath
captures/
project.properties
.project
.settings

View File

@@ -62,7 +62,7 @@ The form and manner of this distribution makes it eligible for export under the
Copyright 2011 Whisper Systems
Copyright 2013-2017 Open Whisper Systems
Copyright 2013-2020 Open Whisper Systems
Licensed under the GPLv3: http://www.gnu.org/licenses/gpl-3.0.html

View File

@@ -3,8 +3,8 @@ host = https://www.transifex.com
lang_map = da_DK:da-rDK,he:iw,id:in,kn_IN:kn-rIN,pt_BR:pt-rBR,pt_PT:pt,qu_EC:qu-rEC,sv_SE:sv-rSE,zh_CN:zh-rCN,zh_HK:zh-rHK,zh_TW:zh-rTW
[signal-android.master]
file_filter = res/values-<lang>/strings.xml
source_file = res/values/strings.xml
file_filter = src/main/res/values-<lang>/strings.xml
source_file = src/main/res/values/strings.xml
source_lang = en
type = ANDROID

436
app/build.gradle Normal file
View File

@@ -0,0 +1,436 @@
import org.signal.signing.ApkSignerUtil
import java.security.MessageDigest
buildscript {
repositories {
google()
maven {
url "https://repo1.maven.org/maven2"
}
jcenter {
content {
includeVersion 'org.jetbrains.trove4j', 'trove4j', '20160824'
}
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.1'
classpath 'androidx.navigation:navigation-safe-args-gradle-plugin:2.1.0'
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.10'
}
}
apply plugin: 'com.android.application'
apply plugin: 'com.google.protobuf'
apply plugin: 'androidx.navigation.safeargs'
apply plugin: 'witness'
apply from: 'translations.gradle'
apply from: 'witness-verifications.gradle'
repositories {
maven {
url "https://raw.github.com/signalapp/maven/master/photoview/releases/"
content {
includeGroupByRegex "com\\.github\\.chrisbanes.*"
}
}
maven {
url "https://raw.github.com/signalapp/maven/master/shortcutbadger/releases/"
content {
includeGroupByRegex "me\\.leolin.*"
}
}
maven {
url "https://raw.github.com/signalapp/maven/master/circular-progress-button/releases/"
content {
includeGroupByRegex "com\\.github\\.dmytrodanylyk\\.circular-progress-button\\.*"
}
}
maven {
url "https://raw.github.com/signalapp/maven/master/sqlcipher/release/"
content {
includeGroupByRegex "org\\.signal.*"
}
}
maven { // textdrawable
url 'https://dl.bintray.com/amulyakhare/maven'
content {
includeGroupByRegex "com\\.amulyakhare.*"
}
}
google()
mavenCentral()
jcenter()
mavenLocal()
}
protobuf {
protoc {
artifact = 'com.google.protobuf:protoc:3.10.0'
}
generateProtoTasks {
all().each { task ->
task.builtins {
java {
option "lite"
}
}
}
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.1.0-beta01'
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.legacy:legacy-support-v13:1.0.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.preference:preference:1.0.0'
implementation 'androidx.legacy:legacy-preference-v14:1.0.0'
implementation 'androidx.gridlayout:gridlayout:1.0.0'
implementation 'androidx.exifinterface:exifinterface:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.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-alpha06"
implementation "androidx.camera:camera-camera2:1.0.0-alpha06"
implementation('com.google.firebase:firebase-messaging:17.3.4') {
exclude group: 'com.google.firebase', module: 'firebase-core'
exclude group: 'com.google.firebase', module: 'firebase-analytics'
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
}
implementation 'com.google.android.gms:play-services-maps:16.1.0'
implementation 'com.google.android.gms:play-services-auth:16.0.1'
implementation 'com.google.android.exoplayer:exoplayer-core:2.9.1'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.9.1'
implementation 'org.conscrypt:conscrypt-android:2.0.0'
implementation 'org.signal:aesgcmprovider:0.0.3'
implementation project(':libsignal-service')
implementation 'org.signal:ringrtc-android:0.3.1'
implementation "me.leolin:ShortcutBadger:1.1.16"
implementation 'se.emilsjolander:stickylistheaders:2.7.0'
implementation 'com.jpardogo.materialtabstrip:library:1.0.9'
implementation 'org.apache.httpcomponents:httpclient-android:4.3.5'
implementation 'com.github.chrisbanes:PhotoView:2.1.3'
implementation 'com.github.bumptech.glide:glide:4.9.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
annotationProcessor 'androidx.annotation:annotation:1.1.0'
implementation 'com.makeramen:roundedimageview:2.1.0'
implementation 'com.pnikosis:materialish-progress:1.5'
implementation 'org.greenrobot:eventbus:3.0.0'
implementation 'pl.tajchert:waitingdots:0.1.0'
implementation 'com.theartofdev.edmodo:android-image-cropper:2.8.0'
implementation 'com.melnykov:floatingactionbutton:1.3.0'
implementation 'com.google.zxing:android-integration:3.1.0'
implementation 'mobi.upod:time-duration-picker:1.1.3'
implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
implementation 'com.google.zxing:core:3.2.1'
implementation ('com.davemorrissey.labs:subsampling-scale-image-view:3.6.0') {
exclude group: 'com.android.support', module: 'support-annotations'
}
implementation ('cn.carbswang.android:NumberPickerView:1.0.9') {
exclude group: 'com.android.support', module: 'appcompat-v7'
}
implementation ('com.tomergoldst.android:tooltips:1.0.6') {
exclude group: 'com.android.support', module: 'appcompat-v7'
}
implementation ('com.klinkerapps:android-smsmms:4.0.1') {
exclude group: 'com.squareup.okhttp', module: 'okhttp'
exclude group: 'com.squareup.okhttp', module: 'okhttp-urlconnection'
}
implementation 'com.annimon:stream:1.1.8'
implementation ('com.takisoft.fix:colorpicker:0.9.1') {
exclude group: 'com.android.support', module: 'appcompat-v7'
exclude group: 'com.android.support', module: 'recyclerview-v7'
}
implementation 'com.airbnb.android:lottie:3.0.7'
implementation 'com.codewaves.stickyheadergrid:stickyheadergrid:0.9.4'
implementation 'com.github.dmytrodanylyk.circular-progress-button:library:1.1.3-S2'
implementation 'org.signal:android-database-sqlcipher:3.5.9-S3'
implementation ('com.googlecode.ez-vcard:ez-vcard:0.9.11') {
exclude group: 'com.fasterxml.jackson.core'
exclude group: 'org.freemarker'
}
testImplementation 'junit:junit:4.12'
testImplementation 'org.assertj:assertj-core:3.11.1'
testImplementation 'org.mockito:mockito-core:1.9.5'
testImplementation 'org.powermock:powermock-api-mockito:1.6.1'
testImplementation 'org.powermock:powermock-module-junit4:1.6.1'
testImplementation 'org.powermock:powermock-module-junit4-rule:1.6.1'
testImplementation 'org.powermock:powermock-classloading-xstream:1.6.1'
testImplementation 'androidx.test:core:1.2.0'
androidTestImplementation 'androidx.multidex:multidex:2.0.1'
androidTestImplementation 'androidx.multidex:multidex-instrumentation:2.0.0'
androidTestImplementation 'com.google.dexmaker:dexmaker:1.2'
androidTestImplementation 'com.google.dexmaker:dexmaker-mockito:1.2'
androidTestImplementation ('org.assertj:assertj-core:1.7.1') {
exclude group: 'org.hamcrest', module: 'hamcrest-core'
}
androidTestImplementation ('com.squareup.assertj:assertj-android:1.1.1') {
exclude group: 'org.hamcrest', module: 'hamcrest-core'
exclude group: 'com.android.support', module: 'support-annotations'
}
testImplementation 'org.robolectric:robolectric:4.2'
testImplementation 'org.robolectric:shadows-multidex:4.2'
}
dependencyVerification {
configuration = '(play|website)(Debug|Release)RuntimeClasspath'
}
def canonicalVersionCode = 587
def canonicalVersionName = "4.53.2"
def postFixSize = 10
def abiPostFix = ['universal' : 0,
'armeabi-v7a' : 1,
'arm64-v8a' : 2,
'x86' : 3,
'x86_64' : 4]
android {
flavorDimensions "none"
compileSdkVersion 28
buildToolsVersion '28.0.3'
useLibrary 'org.apache.http.legacy'
dexOptions {
javaMaxHeapSize "4g"
}
defaultConfig {
versionCode canonicalVersionCode * postFixSize
versionName canonicalVersionName
minSdkVersion 19
targetSdkVersion 28
multiDexEnabled true
vectorDrawables.useSupportLibrary = true
project.ext.set("archivesBaseName", "Signal");
buildConfigField "long", "BUILD_TIMESTAMP", getLastCommitTimestamp() + "L"
buildConfigField "String", "SIGNAL_URL", "\"https://textsecure-service.whispersystems.org\""
buildConfigField "String", "STORAGE_URL", "\"https://storage.signal.org\""
buildConfigField "String", "SIGNAL_CDN_URL", "\"https://cdn.signal.org\""
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", "CONTENT_PROXY_HOST", "\"contentproxy.signal.org\""
buildConfigField "int", "CONTENT_PROXY_PORT", "443"
buildConfigField "String", "USER_AGENT", "\"OWA\""
buildConfigField "boolean", "DEV_BUILD", "false"
buildConfigField "String", "MRENCLAVE", "\"cd6cfc342937b23b1bdd3bbf9721aa5615ac9ff50a75c5527d441cd3276826c9\""
buildConfigField "String", "KEY_BACKUP_ENCLAVE_NAME", "\"f2e2a5004794a6c1bac5c4949eadbc243dd02e02d1a93f10fe24584fb70815d8\""
buildConfigField "String", "KEY_BACKUP_MRENCLAVE", "\"f51f435802ada769e67aaf5744372bb7e7d519eecf996d335eb5b46b872b5789\""
buildConfigField "String", "UNIDENTIFIED_SENDER_TRUST_ROOT", "\"BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF\""
buildConfigField "String[]", "LANGUAGES", "new String[]{\"" + autoResConfig().collect { s -> s.replace('-r', '_') }.join('", "') + '"}'
buildConfigField "int", "CANONICAL_VERSION_CODE", "$canonicalVersionCode"
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
resConfigs autoResConfig()
splits {
abi {
enable true
reset()
include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
universalApk true
}
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
packagingOptions {
exclude 'LICENSE.txt'
exclude 'LICENSE'
exclude 'NOTICE'
exclude 'asm-license.txt'
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
exclude 'META-INF/proguard/androidx-annotations.pro'
}
buildTypes {
debug {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard/proguard-firebase-messaging.pro',
'proguard/proguard-google-play-services.pro',
'proguard/proguard-jackson.pro',
'proguard/proguard-sqlite.pro',
'proguard/proguard-appcompat-v7.pro',
'proguard/proguard-square-okhttp.pro',
'proguard/proguard-square-okio.pro',
'proguard/proguard-spongycastle.pro',
'proguard/proguard-rounded-image-view.pro',
'proguard/proguard-glide.pro',
'proguard/proguard-shortcutbadger.pro',
'proguard/proguard-retrofit.pro',
'proguard/proguard-webrtc.pro',
'proguard/proguard-klinker.pro',
'proguard/proguard-retrolambda.pro',
'proguard/proguard-okhttp.pro',
'proguard/proguard-ez-vcard.pro',
'proguard/proguard.cfg'
testProguardFiles 'proguard/proguard-automation.pro',
'proguard/proguard.cfg'
}
staging {
initWith debug
buildConfigField "String", "SIGNAL_URL", "\"https://textsecure-service-staging.whispersystems.org\""
buildConfigField "String", "STORAGE_URL", "\"https://storage-staging.signal.org\""
buildConfigField "String", "SIGNAL_CDN_URL", "\"https://cdn-staging.signal.org\""
buildConfigField "String", "SIGNAL_CONTACT_DISCOVERY_URL", "\"https://api-staging.directory.signal.org\""
buildConfigField "String", "SIGNAL_KEY_BACKUP_URL", "\"https://api-staging.backup.signal.org\""
buildConfigField "String", "MRENCLAVE", "\"ba4ebb438bc07713819ee6c98d94037747006d7df63fc9e44d2d6f1fec962a79\""
buildConfigField "String", "KEY_BACKUP_ENCLAVE_NAME", "\"b5a865941f95887018c86725cc92308d34a3084dc2b4e7bd2de5e5e1690b50c6\""
buildConfigField "String", "UNIDENTIFIED_SENDER_TRUST_ROOT", "\"BbqY1DzohE4NUZoVF+L18oUPrK3kILllLEJh2UnPSsEx\""
}
release {
minifyEnabled true
proguardFiles = buildTypes.debug.proguardFiles
}
}
productFlavors {
play {
dimension "none"
ext.websiteUpdateUrl = "null"
buildConfigField "boolean", "PLAY_STORE_DISABLED", "false"
buildConfigField "String", "NOPLAY_UPDATE_URL", "$ext.websiteUpdateUrl"
}
website {
dimension "none"
ext.websiteUpdateUrl = "https://updates.signal.org/android"
buildConfigField "boolean", "PLAY_STORE_DISABLED", "true"
buildConfigField "String", "NOPLAY_UPDATE_URL", "\"$ext.websiteUpdateUrl\""
}
}
android.applicationVariants.all { variant ->
variant.outputs.each { output ->
output.outputFileName = output.outputFileName.replace(".apk", "-${variant.versionName}.apk")
def abiName = output.getFilter("ABI") ?: 'universal'
def postFix = abiPostFix.get(abiName, 0)
if (postFix >= postFixSize) throw new AssertionError("postFix is too large")
output.versionCodeOverride = canonicalVersionCode * postFixSize + postFix
}
}
lintOptions {
abortOnError true
baseline file("lint-baseline.xml")
disable "LintError"
}
testOptions {
unitTests {
includeAndroidResources = true
}
}
}
def assembleWebsiteDescriptor = { variant, file ->
if (file.exists()) {
MessageDigest md = MessageDigest.getInstance("SHA-256");
file.eachByte 4096, {bytes, size ->
md.update(bytes, 0, size);
}
String digest = md.digest().collect {String.format "%02x", it}.join();
String url = variant.productFlavors.get(0).ext.websiteUpdateUrl
String apkName = file.getName()
String descriptor = "{" +
"\"versionCode\" : ${canonicalVersionCode * postFixSize + abiPostFix['universal']}," +
"\"versionName\" : \"$canonicalVersionName\"," +
"\"sha256sum\" : \"$digest\"," +
"\"url\" : \"$url/$apkName\"" +
"}"
File descriptorFile = new File(file.getParent(), apkName.replace(".apk", ".json"))
descriptorFile.write(descriptor)
}
}
def signProductionRelease = { variant ->
variant.outputs.collect { output ->
String apkName = output.outputFile.name
File inputFile = new File(output.outputFile.path)
File outputFile = new File(output.outputFile.parent, apkName.replace('-unsigned', ''))
new ApkSignerUtil('sun.security.pkcs11.SunPKCS11',
'pkcs11.config',
'PKCS11',
'file:pkcs11.password').calculateSignature(inputFile.getAbsolutePath(),
outputFile.getAbsolutePath())
inputFile.delete()
outputFile
}
}
task signProductionPlayRelease {
doLast {
signProductionRelease(android.applicationVariants.find { (it.name == 'playRelease') })
}
}
task signProductionWebsiteRelease {
doLast {
def variant = android.applicationVariants.find { (it.name == 'websiteRelease') }
File signedRelease = signProductionRelease(variant).find { it.name.contains('universal') }
assembleWebsiteDescriptor(variant, signedRelease)
}
}
tasks.whenTaskAdded { task ->
if (task.name.equals("assemblePlayRelease")) {
task.finalizedBy signProductionPlayRelease
}
if (task.name.equals("assembleWebsiteRelease")) {
task.finalizedBy signProductionWebsiteRelease
}
}
def getLastCommitTimestamp() {
new ByteArrayOutputStream().withStream { os ->
def result = exec {
executable = 'git'
args = ['log', '-1', '--pretty=format:%ct']
standardOutput = os
}
return os.toString() + "000"
}
}

View File

@@ -1,20 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<issues format="5" by="lint 3.3.2" client="gradle" variant="playRelease" version="3.3.2">
<issue
id="LintError"
message="Unexpected failure during lint analysis of JobManager.java (this is a bug in lint or one of the libraries it depends on)&#xA;&#xA;Stack: `NullPointerException:ClsFileImpl.getMirror(ClsFileImpl.java:343)←ClsElementImpl.getMirror(ClsElementImpl.java:159)←ClsElementImpl.getText(ClsElementImpl.java:202)←InferenceSession.argConstraints(InferenceSession.java:1817)←InferenceSession.isFunctionalTypeMoreSpecific(InferenceSession.java:1748)←InferenceSession.isFunctionalTypeMoreSpecificOnExpression(InferenceSession.java:1729)←JavaMethodsConflictResolver.isFunctionalTypeMoreSpecific(JavaMethodsConflictResolver.java:779)←JavaMethodsConflictResolver.isTypeMoreSpecific(JavaMethodsConflictResolver.java:673)`&#xA;&#xA;You can set environment variable `LINT_PRINT_STACKTRACE=true` to dump a full stacktrace to stdout.">
<location
file="src/org/thoughtcrime/securesms/jobmanager/JobManager.java"/>
</issue>
<issue
id="MissingPermission"
message="Call requires permission which may be rejected by user: code should explicitly check to see if permission is available (with `checkPermission`) or explicitly handle a potential `SecurityException`"
errorLine1=" List&lt;SubscriptionInfo> list = subscriptionManager.getActiveSubscriptionInfoList();"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/org/thoughtcrime/securesms/util/dualsim/SubscriptionManagerCompat.java"
file="src/main/java/org/thoughtcrime/securesms/util/dualsim/SubscriptionManagerCompat.java"
line="101"
column="35"/>
</issue>
@@ -25,7 +18,7 @@
errorLine1=" drawables.getColor(1, 0xff000000);"
errorLine2=" ~">
<location
file="src/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java"
file="src/main/java/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java"
line="187"
column="36"/>
</issue>

View File

@@ -12,5 +12,14 @@
<issue id="ImpliedQuantity" severity="warning" />
<issue id="CanvasSize" severity="error" />
<issue id="HardcodedText" severity="error" />
<issue id="VectorRaster" severity="error" />
<issue id="ButtonOrder" severity="error" />
<issue id="ExtraTranslation" severity="warning" />
<issue id="RestrictedApi" severity="error">
<ignore path="*/org/thoughtcrime/securesms/mediasend/camerax/VideoCapture.java" />
<ignore path="*/org/thoughtcrime/securesms/mediasend/camerax/CameraXModule.java" />
</issue>
</lint>

View File

@@ -1,4 +1,5 @@
-dontoptimize
-dontobfuscate
-keepattributes SourceFile,LineNumberTable
-keep class org.whispersystems.** { *; }
-keep class org.thoughtcrime.securesms.** { *; }
@@ -6,3 +7,5 @@
public void onEvent*(**);
}
# Protobuf lite
-keep class * extends com.google.protobuf.GeneratedMessageLite { *; }

View File

@@ -27,6 +27,7 @@
tools:ignore="ProtectedPermissions"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_MMS"/>
@@ -113,22 +114,20 @@
<meta-data android:name="firebase_messaging_auto_init_enabled" android:value="false" />
<activity android:name="org.thoughtcrime.securesms.WebRtcCallActivity"
android:theme="@style/TextSecure.LightTheme.WebRTCCall"
android:excludeFromRecents="true"
android:screenOrientation="portrait"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|screenSize|fontScale"
android:launchMode="singleTask"/>
<activity android:name=".CountrySelectionActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".InviteActivity"
android:theme="@style/TextSecure.HighlightTheme"
android:theme="@style/Signal.Light.NoActionBar.Invite"
android:windowSoftInputMode="stateHidden"
android:parentActivityName=".ConversationListActivity"
android:parentActivityName=".MainActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="org.thoughtcrime.securesms.ConversationListActivity" />
android:value="org.thoughtcrime.securesms.MainActivity" />
</activity>
<activity android:name=".PromptMmsActivity"
@@ -189,18 +188,18 @@
<data android:scheme="sgnl"
android:host="addstickers" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https"
android:host="signal.art"
android:pathPrefix="/addstickers"/>
</intent-filter>
</activity>
<activity android:name=".ConversationListActivity"
android:label="@string/app_name"
android:launchMode="singleTask"
android:theme="@style/TextSecure.LightNoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:exported="true" />
<activity-alias android:name=".RoutingActivity"
android:targetActivity=".ConversationListActivity"
android:targetActivity=".MainActivity"
android:exported="true">
<intent-filter>
@@ -216,24 +215,14 @@
</activity-alias>
<activity android:name=".ConversationListArchiveActivity"
android:label="@string/AndroidManifest_archived_conversations"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:parentActivityName=".ConversationListActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="org.thoughtcrime.securesms.ConversationListActivity" />
</activity>
<activity android:name=".conversation.ConversationActivity"
android:windowSoftInputMode="stateUnchanged"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:parentActivityName=".ConversationListActivity">
android:parentActivityName=".MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="org.thoughtcrime.securesms.ConversationListActivity" />
android:value="org.thoughtcrime.securesms.MainActivity" />
</activity>
<activity android:name=".longmessage.LongMessageActivity" />
@@ -261,13 +250,13 @@
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".DatabaseUpgradeActivity"
<activity android:name=".migrations.ApplicationMigrationActivity"
android:theme="@style/NoAnimation.Theme.AppCompat.Light.DarkActionBar"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".ExperienceUpgradeActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
android:theme="@style/TextSecure.LightNoActionBar"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
@@ -298,10 +287,11 @@
android:windowSoftInputMode="stateHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".mediasend.MediaSendActivity"
android:theme="@style/TextSecure.FullScreenMedia"
android:windowSoftInputMode="stateHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".mediasend.MediaSendActivity"
android:theme="@style/TextSecure.FullScreenMedia"
android:windowSoftInputMode="stateHidden"
android:launchMode="singleTop"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".PassphraseChangeActivity"
android:label="@string/AndroidManifest__change_passphrase"
@@ -318,24 +308,12 @@
</intent-filter>
</activity>
<activity android:name=".registration.WelcomeActivity"
<activity android:name=".registration.RegistrationNavigationActivity"
android:launchMode="singleTask"
android:theme="@style/TextSecure.LightRegistrationTheme"
android:windowSoftInputMode="stateUnchanged"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".RegistrationActivity"
android:launchMode="singleTask"
android:theme="@style/TextSecure.LightRegistrationTheme"
android:windowSoftInputMode="stateUnchanged"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".registration.CaptchaActivity"
android:launchMode="singleTask"
android:theme="@style/TextSecure.LightNoActionBar"
android:windowSoftInputMode="stateUnchanged"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".revealable.ViewOnceMessageActivity"
android:launchMode="singleTask"
android:theme="@style/TextSecure.FullScreenMedia"
@@ -364,10 +342,9 @@
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".MediaOverviewActivity"
<activity android:name=".mediaoverview.MediaOverviewActivity"
android:theme="@style/TextSecure.LightNoActionBar"
android:windowSoftInputMode="stateHidden"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".DummyActivity"
@@ -425,7 +402,7 @@
android:theme="@style/TextSecure.LightTheme"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".scribbles.StickerSelectActivity"
<activity android:name=".scribbles.ImageEditorStickerSelectActivity"
android:theme="@style/TextSecure.DarkTheme"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
@@ -469,7 +446,18 @@
<activity
android:name=".maps.PlacePickerActivity"
android:label="@string/PlacePickerActivity_title"
android:theme="@style/TextSecure.LightNoActionBar" />
android:theme="@style/TextSecure.LightNoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity
android:name=".usernames.ProfileEditActivityV2"
android:theme="@style/TextSecure.LightNoActionBar"
android:windowSoftInputMode="adjustResize"/>
<activity android:name=".MainActivity"
android:theme="@style/TextSecure.LightNoActionBar"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" />
<service android:enabled="true" android:name="org.thoughtcrime.securesms.service.WebRtcCallService"/>
<service android:enabled="true" android:name=".service.ApplicationMigrationService"/>

View File

Before

Width:  |  Height:  |  Size: 211 KiB

After

Width:  |  Height:  |  Size: 211 KiB

View File

Before

Width:  |  Height:  |  Size: 447 KiB

After

Width:  |  Height:  |  Size: 447 KiB

View File

Before

Width:  |  Height:  |  Size: 307 KiB

After

Width:  |  Height:  |  Size: 307 KiB

View File

Before

Width:  |  Height:  |  Size: 387 KiB

After

Width:  |  Height:  |  Size: 387 KiB

View File

Before

Width:  |  Height:  |  Size: 494 KiB

After

Width:  |  Height:  |  Size: 494 KiB

View File

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

View File

Before

Width:  |  Height:  |  Size: 952 KiB

After

Width:  |  Height:  |  Size: 952 KiB

View File

Before

Width:  |  Height:  |  Size: 862 KiB

After

Width:  |  Height:  |  Size: 862 KiB

View File

Before

Width:  |  Height:  |  Size: 364 KiB

After

Width:  |  Height:  |  Size: 364 KiB

View File

Before

Width:  |  Height:  |  Size: 567 KiB

After

Width:  |  Height:  |  Size: 567 KiB

View File

Before

Width:  |  Height:  |  Size: 376 KiB

After

Width:  |  Height:  |  Size: 376 KiB

View File

@@ -18,6 +18,7 @@ package org.thoughtcrime.securesms;
import android.annotation.SuppressLint;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.camera.camera2.Camera2AppConfig;
import androidx.camera.core.CameraX;
import androidx.lifecycle.DefaultLifecycleObserver;
@@ -33,30 +34,32 @@ import com.google.android.gms.security.ProviderInstaller;
import org.conscrypt.Conscrypt;
import org.signal.aesgcmprovider.AesGcmProvider;
import org.signal.ringrtc.CallConnectionFactory;
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;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencyProvider;
import org.thoughtcrime.securesms.gcm.FcmJobService;
import org.thoughtcrime.securesms.insights.InsightsOptOut;
import org.thoughtcrime.securesms.jobmanager.JobManager;
import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer;
import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
import org.thoughtcrime.securesms.jobs.FastJobStorage;
import org.thoughtcrime.securesms.jobs.FcmRefreshJob;
import org.thoughtcrime.securesms.jobs.JobManagerFactories;
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
import org.thoughtcrime.securesms.jobs.RefreshUnidentifiedDeliveryAbilityJob;
import org.thoughtcrime.securesms.jobs.StickerPackDownloadJob;
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.UncaughtExceptionLogger;
import org.thoughtcrime.securesms.mediasend.camerax.CameraXUtil;
import org.thoughtcrime.securesms.migrations.ApplicationMigrations;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.ringrtc.RingRtcLogger;
import org.thoughtcrime.securesms.service.DirectoryRefreshListener;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
import org.thoughtcrime.securesms.service.IncomingMessageObserver;
@@ -66,10 +69,11 @@ import org.thoughtcrime.securesms.revealable.ViewOnceMessageManager;
import org.thoughtcrime.securesms.service.RotateSenderCertificateListener;
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
import org.thoughtcrime.securesms.service.UpdateApkRefreshListener;
import org.thoughtcrime.securesms.stickers.BlessedPacks;
import org.thoughtcrime.securesms.util.FrameRateTracker;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageContextWrapper;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.PeerConnectionFactory.InitializationOptions;
import org.webrtc.voiceengine.WebRtcAudioManager;
import org.webrtc.voiceengine.WebRtcAudioUtils;
import org.whispersystems.libsignal.logging.SignalProtocolLoggerProvider;
@@ -92,10 +96,9 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
private static final String TAG = ApplicationContext.class.getSimpleName();
private ExpiringMessageManager expiringMessageManager;
private ViewOnceMessageManager viewOnceMessageManager;
private ViewOnceMessageManager viewOnceMessageManager;
private TypingStatusRepository typingStatusRepository;
private TypingStatusSender typingStatusSender;
private JobManager jobManager;
private IncomingMessageObserver incomingMessageObserver;
private PersistentLogger persistentLogger;
@@ -113,7 +116,8 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
initializeLogging();
initializeCrashHandling();
initializeAppDependencies();
initializeJobManager();
initializeFirstEverAppLaunch();
initializeApplicationMigrations();
initializeMessageRetrieval();
initializeExpiringMessageManager();
initializeRevealableMessageManager();
@@ -123,22 +127,28 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
initializeSignedPreKeyCheck();
initializePeriodicTasks();
initializeCircumvention();
initializeWebRtc();
initializeRingRtc();
initializePendingMessages();
initializeUnidentifiedDeliveryAbilityRefresh();
initializeBlobProvider();
initializeCameraX();
NotificationChannels.create(this);
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
if (Build.VERSION.SDK_INT < 21) {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
ApplicationDependencies.getJobManager().beginJobLoop();
}
@Override
public void onStart(@NonNull LifecycleOwner owner) {
isAppVisible = true;
Log.i(TAG, "App is now visible.");
ApplicationDependencies.getRecipientCache().warmUp();
executePendingContactSync();
KeyCachingService.onAppForegrounded(this);
MessageNotifier.cancelMessagesPending(this);
ApplicationDependencies.getFrameRateTracker().begin();
}
@Override
@@ -147,10 +157,7 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
Log.i(TAG, "App is no longer visible.");
KeyCachingService.onAppBackgrounded(this);
MessageNotifier.setVisibleThread(-1);
}
public JobManager getJobManager() {
return jobManager;
ApplicationDependencies.getFrameRateTracker().end();
}
public ExpiringMessageManager getExpiringMessageManager() {
@@ -213,14 +220,8 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionLogger(originalHandler));
}
private void initializeJobManager() {
this.jobManager = new JobManager(this, new JobManager.Configuration.Builder()
.setDataSerializer(new JsonDataSerializer())
.setJobFactories(JobManagerFactories.getJobFactories(this))
.setConstraintFactories(JobManagerFactories.getConstraintFactories(this))
.setConstraintObservers(JobManagerFactories.getConstraintObservers(this))
.setJobStorage(new FastJobStorage(DatabaseFactory.getJobDatabase(this)))
.build());
private void initializeApplicationMigrations() {
ApplicationMigrations.onApplicationCreate(this, ApplicationDependencies.getJobManager());
}
public void initializeMessageRetrieval() {
@@ -228,7 +229,26 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
}
private void initializeAppDependencies() {
ApplicationDependencies.init(new ApplicationDependencyProvider(this, new SignalServiceNetworkAccess(this)));
ApplicationDependencies.init(this, new ApplicationDependencyProvider(this, new SignalServiceNetworkAccess(this)));
}
private void initializeFirstEverAppLaunch() {
if (TextSecurePreferences.getFirstInstallVersion(this) == -1) {
if (!SQLCipherOpenHelper.databaseFileExists(this)) {
Log.i(TAG, "First ever app launch!");
InsightsOptOut.userRequestedOptOut(this);
TextSecurePreferences.setAppMigrationVersion(this, ApplicationMigrations.CURRENT_VERSION);
TextSecurePreferences.setJobManagerVersion(this, JobManager.CURRENT_VERSION);
TextSecurePreferences.setLastExperienceVersionCode(this, Util.getCanonicalVersionCode());
TextSecurePreferences.setHasSeenStickerIntroTooltip(this, true);
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forInstall(BlessedPacks.ZOZO.getPackId(), BlessedPacks.ZOZO.getPackKey(), false));
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forInstall(BlessedPacks.BANDIT.getPackId(), BlessedPacks.BANDIT.getPackKey(), false));
}
Log.i(TAG, "Setting first install version to " + BuildConfig.CANONICAL_VERSION_CODE);
TextSecurePreferences.setFirstInstallVersion(this, BuildConfig.CANONICAL_VERSION_CODE);
}
}
private void initializeGcmCheck() {
@@ -236,14 +256,14 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
long nextSetTime = TextSecurePreferences.getFcmTokenLastSetTime(this) + TimeUnit.HOURS.toMillis(6);
if (TextSecurePreferences.getFcmToken(this) == null || nextSetTime <= System.currentTimeMillis()) {
this.jobManager.add(new FcmRefreshJob());
ApplicationDependencies.getJobManager().add(new FcmRefreshJob());
}
}
}
private void initializeSignedPreKeyCheck() {
if (!TextSecurePreferences.isSignedPreKeyRegistered(this)) {
jobManager.add(new CreateSignedPreKeyJob(this));
ApplicationDependencies.getJobManager().add(new CreateSignedPreKeyJob(this));
}
}
@@ -274,7 +294,7 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
}
}
private void initializeWebRtc() {
private void initializeRingRtc() {
try {
Set<String> HARDWARE_AEC_BLACKLIST = new HashSet<String>() {{
add("Pixel");
@@ -303,7 +323,7 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
WebRtcAudioManager.setBlacklistDeviceForOpenSLESUsage(true);
}
PeerConnectionFactory.initialize(InitializationOptions.builder(this).createInitializationOptions());
CallConnectionFactory.initialize(this, new RingRtcLogger());
} catch (UnsatisfiedLinkError e) {
Log.w(TAG, e);
}
@@ -330,7 +350,7 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
private void executePendingContactSync() {
if (TextSecurePreferences.needsFullContactSync(this)) {
ApplicationContext.getInstance(this).getJobManager().add(new MultiDeviceContactUpdateJob(this, true));
ApplicationDependencies.getJobManager().add(new MultiDeviceContactUpdateJob(true));
}
}
@@ -340,18 +360,12 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
if (Build.VERSION.SDK_INT >= 26) {
FcmJobService.schedule(this);
} else {
ApplicationContext.getInstance(this).getJobManager().add(new PushNotificationReceiveJob(this));
ApplicationDependencies.getJobManager().add(new PushNotificationReceiveJob(this));
}
TextSecurePreferences.setNeedsMessagePull(this, false);
}
}
private void initializeUnidentifiedDeliveryAbilityRefresh() {
if (TextSecurePreferences.isMultiDevice(this) && !TextSecurePreferences.isUnidentifiedDeliveryEnabled(this)) {
jobManager.add(new RefreshUnidentifiedDeliveryAbilityJob());
}
}
private void initializeBlobProvider() {
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
BlobProvider.getInstance().onSessionStart(this);
@@ -360,12 +374,14 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
@SuppressLint("RestrictedApi")
private void initializeCameraX() {
if (Build.VERSION.SDK_INT >= 21) {
try {
CameraX.init(this, Camera2AppConfig.create(this));
} catch (Throwable t) {
Log.w(TAG, "Failed to initialize CameraX.");
}
if (CameraXUtil.isSupported()) {
new Thread(() -> {
try {
CameraX.init(this, Camera2AppConfig.create(this));
} catch (Throwable t) {
Log.w(TAG, "Failed to initialize CameraX.");
}
}, "signal-camerax-initialization").start();
}
}

View File

@@ -17,19 +17,13 @@
*/
package org.thoughtcrime.securesms;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.graphics.PorterDuff;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
@@ -42,11 +36,15 @@ import org.thoughtcrime.securesms.preferences.ChatsPreferenceFragment;
import org.thoughtcrime.securesms.preferences.CorrectedPreferenceFragment;
import org.thoughtcrime.securesms.preferences.NotificationsPreferenceFragment;
import org.thoughtcrime.securesms.preferences.SmsMmsPreferenceFragment;
import org.thoughtcrime.securesms.preferences.StoragePreferenceFragment;
import org.thoughtcrime.securesms.preferences.widgets.ProfilePreference;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.usernames.ProfileEditActivityV2;
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.
@@ -67,6 +65,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
private static final String PREFERENCE_CATEGORY_APP_PROTECTION = "preference_category_app_protection";
private static final String PREFERENCE_CATEGORY_APPEARANCE = "preference_category_appearance";
private static final String PREFERENCE_CATEGORY_CHATS = "preference_category_chats";
private static final String PREFERENCE_CATEGORY_STORAGE = "preference_category_storage";
private static final String PREFERENCE_CATEGORY_DEVICES = "preference_category_devices";
private static final String PREFERENCE_CATEGORY_ADVANCED = "preference_category_advanced";
@@ -112,7 +111,8 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
if (fragmentManager.getBackStackEntryCount() > 0) {
fragmentManager.popBackStack();
} else {
Intent intent = new Intent(this, ConversationListActivity.class);
// TODO [greyson] Navigation
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
@@ -151,14 +151,21 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_APPEARANCE));
this.findPreference(PREFERENCE_CATEGORY_CHATS)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_CHATS));
this.findPreference(PREFERENCE_CATEGORY_STORAGE)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_STORAGE));
this.findPreference(PREFERENCE_CATEGORY_DEVICES)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_DEVICES));
this.findPreference(PREFERENCE_CATEGORY_ADVANCED)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_ADVANCED));
if (VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
tintIcons(getActivity());
}
tintIcons();
}
private void tintIcons() {
if (Build.VERSION.SDK_INT >= 21) return;
Preference preference = this.findPreference(PREFERENCE_CATEGORY_SMS_MMS);
preference.getIcon().setColorFilter(ThemeUtil.getThemedColor(requireContext(), R.attr.icon_tint), PorterDuff.Mode.SRC_IN);
}
@Override
@@ -197,38 +204,6 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
}
}
@TargetApi(11)
private void tintIcons(Context context) {
Drawable sms = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_textsms_white_24dp));
Drawable notifications = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_notifications_white_24dp));
Drawable privacy = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_security_white_24dp));
Drawable appearance = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_brightness_6_white_24dp));
Drawable chats = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_forum_white_24dp));
Drawable devices = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_laptop_white_24dp));
Drawable advanced = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.ic_advanced_white_24dp));
int[] tintAttr = new int[]{R.attr.pref_icon_tint};
TypedArray typedArray = context.obtainStyledAttributes(tintAttr);
int color = typedArray.getColor(0, 0x0);
typedArray.recycle();
DrawableCompat.setTint(sms, color);
DrawableCompat.setTint(notifications, color);
DrawableCompat.setTint(privacy, color);
DrawableCompat.setTint(appearance, color);
DrawableCompat.setTint(chats, color);
DrawableCompat.setTint(devices, color);
DrawableCompat.setTint(advanced, color);
this.findPreference(PREFERENCE_CATEGORY_SMS_MMS).setIcon(sms);
this.findPreference(PREFERENCE_CATEGORY_NOTIFICATIONS).setIcon(notifications);
this.findPreference(PREFERENCE_CATEGORY_APP_PROTECTION).setIcon(privacy);
this.findPreference(PREFERENCE_CATEGORY_APPEARANCE).setIcon(appearance);
this.findPreference(PREFERENCE_CATEGORY_CHATS).setIcon(chats);
this.findPreference(PREFERENCE_CATEGORY_DEVICES).setIcon(devices);
this.findPreference(PREFERENCE_CATEGORY_ADVANCED).setIcon(advanced);
}
private class CategoryClickListener implements Preference.OnPreferenceClickListener {
private String category;
@@ -256,6 +231,9 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
case PREFERENCE_CATEGORY_CHATS:
fragment = new ChatsPreferenceFragment();
break;
case PREFERENCE_CATEGORY_STORAGE:
fragment = new StoragePreferenceFragment();
break;
case PREFERENCE_CATEGORY_DEVICES:
Intent intent = new Intent(getActivity(), DeviceActivity.class);
startActivity(intent);
@@ -288,11 +266,14 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
private class ProfileClickListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent intent = new Intent(preference.getContext(), CreateProfileActivity.class);
intent.putExtra(CreateProfileActivity.EXCLUDE_SYSTEM, true);
if (FeatureFlags.USERNAMES) {
requireActivity().startActivity(ProfileEditActivityV2.getLaunchIntent(requireContext()));
} else {
Intent intent = new Intent(preference.getContext(), CreateProfileActivity.class);
intent.putExtra(CreateProfileActivity.EXCLUDE_SYSTEM, true);
getActivity().startActivity(intent);
// ((BaseActionBarActivity)getActivity()).startActivitySceneTransition(intent, getActivity().findViewById(R.id.avatar), "avatar");
requireActivity().startActivity(intent);
}
return true;
}
}

View File

@@ -5,12 +5,13 @@ import androidx.annotation.Nullable;
import android.view.View;
import org.thoughtcrime.securesms.contactshare.Contact;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.database.model.ReactionRecord;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.stickers.StickerLocator;
import org.whispersystems.libsignal.util.guava.Optional;
@@ -36,12 +37,13 @@ public interface BindableConversationItem extends Unbindable {
interface EventListener {
void onQuoteClicked(MmsMessageRecord messageRecord);
void onLinkPreviewClicked(@NonNull LinkPreview linkPreview);
void onMoreTextClicked(@NonNull Address conversationAddress, long messageId, boolean isMms);
void onMoreTextClicked(@NonNull RecipientId conversationRecipientId, long messageId, boolean isMms);
void onStickerClicked(@NonNull StickerLocator stickerLocator);
void onViewOnceMessageClicked(@NonNull MmsMessageRecord messageRecord);
void onSharedContactDetailsClicked(@NonNull Contact contact, @NonNull View avatarTransitionView);
void onAddToContactsClicked(@NonNull Contact contact);
void onMessageSharedContactClicked(@NonNull List<Recipient> choices);
void onInviteSharedContactClicked(@NonNull List<Recipient> choices);
void onReactionClicked(long messageId, boolean isMms);
}
}

View File

@@ -17,12 +17,14 @@ import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import org.thoughtcrime.securesms.database.Address;
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.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
@@ -78,6 +80,12 @@ public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity
getLoaderManager().initLoader(0, null, this);
}
@Override
public void onStart() {
super.onStart();
getLoaderManager().restartLoader(0, null, this);
}
@Override
public void onActivityCreated(Bundle bundle) {
super.onActivityCreated(bundle);
@@ -107,7 +115,7 @@ public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Recipient recipient = ((BlockedContactListItem)view).getRecipient();
Intent intent = new Intent(getActivity(), RecipientPreferenceActivity.class);
intent.putExtra(RecipientPreferenceActivity.ADDRESS_EXTRA, recipient.getAddress());
intent.putExtra(RecipientPreferenceActivity.RECIPIENT_ID, recipient.getId());
startActivity(intent);
}
@@ -129,8 +137,8 @@ public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity
@Override
public void bindView(View view, Context context, Cursor cursor) {
String address = cursor.getString(1);
Recipient recipient = Recipient.from(context, Address.fromSerialized(address), true);
RecipientId recipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RecipientDatabase.ID)));
LiveRecipient recipient = Recipient.live(recipientId);
((BlockedContactListItem) view).set(glideRequests, recipient);
}

View File

@@ -5,14 +5,14 @@ import android.content.Context;
import android.content.DialogInterface;
import android.database.Cursor;
import android.os.AsyncTask;
import androidx.appcompat.app.AlertDialog;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
@@ -20,12 +20,16 @@ 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.jobs.PushDecryptJob;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobs.PushDecryptMessageJob;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.VerifySpan;
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
@@ -46,8 +50,8 @@ public class ConfirmIdentityDialog extends AlertDialog {
{
super(context);
Recipient recipient = Recipient.from(context, mismatch.getAddress(), false);
String name = recipient.toShortString();
Recipient recipient = Recipient.resolved(mismatch.getRecipientId(context));
String name = recipient.toShortString(context);
String introduction = context.getString(R.string.ConfirmIdentityDialog_your_safety_number_with_s_has_changed, name, name);
SpannableString spannableString = new SpannableString(introduction + " " +
context.getString(R.string.ConfirmIdentityDialog_you_may_wish_to_verify_your_safety_number_with_this_contact));
@@ -59,7 +63,7 @@ public class ConfirmIdentityDialog extends AlertDialog {
setTitle(name);
setMessage(spannableString);
setButton(AlertDialog.BUTTON_POSITIVE, context.getString(R.string.ConfirmIdentityDialog_accept), new AcceptListener(messageRecord, mismatch, recipient.getAddress()));
setButton(AlertDialog.BUTTON_POSITIVE, context.getString(R.string.ConfirmIdentityDialog_accept), new AcceptListener(messageRecord, mismatch, recipient.getId()));
setButton(AlertDialog.BUTTON_NEGATIVE, context.getString(android.R.string.cancel), new CancelListener());
}
@@ -78,12 +82,12 @@ public class ConfirmIdentityDialog extends AlertDialog {
private final MessageRecord messageRecord;
private final IdentityKeyMismatch mismatch;
private final Address address;
private final RecipientId recipientId;
private AcceptListener(MessageRecord messageRecord, IdentityKeyMismatch mismatch, Address address) {
private AcceptListener(MessageRecord messageRecord, IdentityKeyMismatch mismatch, RecipientId recipientId) {
this.messageRecord = messageRecord;
this.mismatch = mismatch;
this.address = address;
this.recipientId = recipientId;
}
@SuppressLint("StaticFieldLeak")
@@ -94,7 +98,7 @@ public class ConfirmIdentityDialog extends AlertDialog {
@Override
protected Void doInBackground(Void... params) {
synchronized (SESSION_LOCK) {
SignalProtocolAddress mismatchAddress = new SignalProtocolAddress(address.toPhoneString(), 1);
SignalProtocolAddress mismatchAddress = new SignalProtocolAddress(Recipient.resolved(recipientId).requireServiceId(), 1);
TextSecureIdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(getContext());
identityKeyStore.saveIdentity(mismatchAddress, mismatch.getIdentityKey(), true);
@@ -137,17 +141,17 @@ public class ConfirmIdentityDialog extends AlertDialog {
if (messageRecord.isMms()) {
mmsDatabase.removeMismatchedIdentity(messageRecord.getId(),
mismatch.getAddress(),
mismatch.getRecipientId(getContext()),
mismatch.getIdentityKey());
if (messageRecord.getRecipient().isPushGroupRecipient()) {
MessageSender.resendGroupMessage(getContext(), messageRecord, mismatch.getAddress());
if (messageRecord.getRecipient().isPushGroup()) {
MessageSender.resendGroupMessage(getContext(), messageRecord, Recipient.resolved(mismatch.getRecipientId(getContext())).getId());
} else {
MessageSender.resend(getContext(), messageRecord);
}
} else {
smsDatabase.removeMismatchedIdentity(messageRecord.getId(),
mismatch.getAddress(),
mismatch.getRecipientId(getContext()),
mismatch.getIdentityKey());
MessageSender.resend(getContext(), messageRecord);
@@ -160,13 +164,13 @@ public class ConfirmIdentityDialog extends AlertDialog {
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(getContext());
smsDatabase.removeMismatchedIdentity(messageRecord.getId(),
mismatch.getAddress(),
mismatch.getRecipientId(getContext()),
mismatch.getIdentityKey());
boolean legacy = !messageRecord.isContentBundleKeyExchange();
SignalServiceEnvelope envelope = new SignalServiceEnvelope(SignalServiceProtos.Envelope.Type.PREKEY_BUNDLE_VALUE,
messageRecord.getIndividualRecipient().getAddress().toPhoneString(),
Optional.of(RecipientUtil.toSignalServiceAddress(getContext(), messageRecord.getIndividualRecipient())),
messageRecord.getRecipientDeviceId(),
messageRecord.getDateSent(),
legacy ? Base64.decode(messageRecord.getBody()) : null,
@@ -175,9 +179,7 @@ public class ConfirmIdentityDialog extends AlertDialog {
long pushId = pushDatabase.insert(envelope);
ApplicationContext.getInstance(getContext())
.getJobManager()
.add(new PushDecryptJob(getContext(), pushId, messageRecord.getId()));
ApplicationDependencies.getJobManager().add(new PushDecryptMessageJob(getContext(), pushId, messageRecord.getId()));
} catch (IOException e) {
throw new AssertionError(e);
}

View File

@@ -20,16 +20,20 @@ import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.components.ContactFilterToolbar;
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
import org.thoughtcrime.securesms.util.DirectoryHelper;
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.whispersystems.libsignal.util.guava.Optional;
import java.io.IOException;
import java.lang.ref.WeakReference;
@@ -63,7 +67,7 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActionB
protected void onCreate(Bundle icicle, boolean ready) {
if (!getIntent().hasExtra(ContactSelectionListFragment.DISPLAY_MODE)) {
int displayMode = TextSecurePreferences.isSmsEnabled(this) ? DisplayMode.FLAG_ALL
: DisplayMode.FLAG_PUSH | DisplayMode.FLAG_GROUPS;
: DisplayMode.FLAG_PUSH | DisplayMode.FLAG_ACTIVE_GROUPS | DisplayMode.FLAG_INACTIVE_GROUPS;
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, displayMode);
}
@@ -112,10 +116,10 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActionB
}
@Override
public void onContactSelected(String number) {}
public void onContactSelected(Optional<RecipientId> recipientId, String number) {}
@Override
public void onContactDeselected(String number) {}
public void onContactDeselected(Optional<RecipientId> recipientId, String number) {}
private static class RefreshDirectoryTask extends AsyncTask<Context, Void, Void> {
@@ -127,7 +131,6 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActionB
@Override
protected Void doInBackground(Context... params) {
try {
DirectoryHelper.refreshDirectory(params[0], true);
} catch (IOException e) {

View File

@@ -19,16 +19,10 @@ package org.thoughtcrime.securesms;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -37,6 +31,16 @@ import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.pnikosis.materialishprogress.ProgressWheel;
import org.thoughtcrime.securesms.components.RecyclerViewFastScroller;
@@ -44,14 +48,22 @@ import org.thoughtcrime.securesms.contacts.ContactSelectionListAdapter;
import org.thoughtcrime.securesms.contacts.ContactSelectionListItem;
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader;
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
import org.thoughtcrime.securesms.contacts.SelectedContact;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.util.DirectoryHelper;
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.UsernameUtil;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.adapter.FixedViewsAdapter;
import org.thoughtcrime.securesms.util.adapter.RecyclerViewConcatenateAdapterStickyHeader;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
import org.whispersystems.libsignal.util.guava.Optional;
import java.io.IOException;
import java.util.LinkedList;
@@ -64,28 +76,41 @@ import java.util.Set;
* @author Moxie Marlinspike
*
*/
public class ContactSelectionListFragment extends Fragment
implements LoaderManager.LoaderCallbacks<Cursor>
public final class ContactSelectionListFragment extends Fragment
implements LoaderManager.LoaderCallbacks<Cursor>
{
@SuppressWarnings("unused")
private static final String TAG = ContactSelectionListFragment.class.getSimpleName();
private static final String TAG = Log.tag(ContactSelectionListFragment.class);
public static final String DISPLAY_MODE = "display_mode";
public static final String MULTI_SELECT = "multi_select";
public static final String REFRESHABLE = "refreshable";
public static final String RECENTS = "recents";
private TextView emptyText;
private Set<String> selectedContacts;
private OnContactSelectedListener onContactSelectedListener;
private SwipeRefreshLayout swipeRefresh;
private View showContactsLayout;
private Button showContactsButton;
private TextView showContactsDescription;
private ProgressWheel showContactsProgress;
private String cursorFilter;
private RecyclerView recyclerView;
private RecyclerViewFastScroller fastScroller;
private TextView emptyText;
private Set<SelectedContact> selectedContacts;
private OnContactSelectedListener onContactSelectedListener;
private SwipeRefreshLayout swipeRefresh;
private View showContactsLayout;
private Button showContactsButton;
private TextView showContactsDescription;
private ProgressWheel showContactsProgress;
private String cursorFilter;
private RecyclerView recyclerView;
private RecyclerViewFastScroller fastScroller;
private ContactSelectionListAdapter cursorRecyclerViewAdapter;
@Nullable private FixedViewsAdapter footerAdapter;
@Nullable private InviteCallback inviteCallback;
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (context instanceof InviteCallback) {
inviteCallback = (InviteCallback) context;
}
}
@Override
public void onActivityCreated(Bundle icicle) {
@@ -144,8 +169,8 @@ public class ContactSelectionListFragment extends Fragment
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
}
public @NonNull List<String> getSelectedContacts() {
List<String> selected = new LinkedList<>();
public @NonNull List<SelectedContact> getSelectedContacts() {
List<SelectedContact> selected = new LinkedList<>();
if (selectedContacts != null) {
selected.addAll(selectedContacts);
}
@@ -158,14 +183,31 @@ public class ContactSelectionListFragment extends Fragment
}
private void initializeCursor() {
ContactSelectionListAdapter adapter = new ContactSelectionListAdapter(getActivity(),
GlideApp.with(this),
null,
new ListClickListener(),
isMulti());
selectedContacts = adapter.getSelectedContacts();
recyclerView.setAdapter(adapter);
recyclerView.addItemDecoration(new StickyHeaderDecoration(adapter, true, true));
cursorRecyclerViewAdapter = new ContactSelectionListAdapter(requireContext(),
GlideApp.with(this),
null,
new ListClickListener(),
isMulti());
selectedContacts = cursorRecyclerViewAdapter.getSelectedContacts();
RecyclerViewConcatenateAdapterStickyHeader concatenateAdapter = new RecyclerViewConcatenateAdapterStickyHeader();
concatenateAdapter.addAdapter(cursorRecyclerViewAdapter);
if (inviteCallback != null) {
footerAdapter = new FixedViewsAdapter(createInviteActionView(inviteCallback));
footerAdapter.hide();
concatenateAdapter.addAdapter(footerAdapter);
}
recyclerView.setAdapter(concatenateAdapter);
recyclerView.addItemDecoration(new StickyHeaderDecoration(concatenateAdapter, true, true));
}
private View createInviteActionView(@NonNull InviteCallback inviteCallback) {
View view = LayoutInflater.from(requireContext())
.inflate(R.layout.contact_selection_invite_action_item, (ViewGroup) requireView(), false);
view.setOnClickListener(v -> inviteCallback.onInvite());
return view;
}
private void initializeNoContactsPermission() {
@@ -192,7 +234,7 @@ public class ContactSelectionListFragment extends Fragment
public void setQueryFilter(String filter) {
this.cursorFilter = filter;
this.getLoaderManager().restartLoader(0, null, this);
LoaderManager.getInstance(this).restartLoader(0, null, this);
}
public void resetQueryFilter() {
@@ -220,28 +262,38 @@ public class ContactSelectionListFragment extends Fragment
}
@Override
public void onLoadFinished(@NonNull Loader<Cursor> loader, Cursor data) {
public void onLoadFinished(@NonNull Loader<Cursor> loader, @Nullable Cursor data) {
swipeRefresh.setVisibility(View.VISIBLE);
showContactsLayout.setVisibility(View.GONE);
((CursorRecyclerViewAdapter) recyclerView.getAdapter()).changeCursor(data);
cursorRecyclerViewAdapter.changeCursor(data);
if (footerAdapter != null) {
footerAdapter.show();
}
emptyText.setText(R.string.contact_selection_group_activity__no_contacts);
boolean useFastScroller = (recyclerView.getAdapter().getItemCount() > 20);
boolean useFastScroller = data != null && data.getCount() > 20;
recyclerView.setVerticalScrollBarEnabled(!useFastScroller);
if (useFastScroller) {
fastScroller.setVisibility(View.VISIBLE);
fastScroller.setRecyclerView(recyclerView);
} else {
fastScroller.setRecyclerView(null);
fastScroller.setVisibility(View.GONE);
}
}
@Override
public void onLoaderReset(@NonNull Loader<Cursor> loader) {
((CursorRecyclerViewAdapter) recyclerView.getAdapter()).changeCursor(null);
cursorRecyclerViewAdapter.changeCursor(null);
fastScroller.setVisibility(View.GONE);
}
@SuppressLint("StaticFieldLeak")
private void handleContactPermissionGranted() {
final Context context = requireContext();
new AsyncTask<Void, Void, Boolean>() {
@Override
protected void onPreExecute() {
@@ -256,7 +308,7 @@ public class ContactSelectionListFragment extends Fragment
@Override
protected Boolean doInBackground(Void... voids) {
try {
DirectoryHelper.refreshDirectory(getContext(), false);
DirectoryHelper.refreshDirectory(context, false);
return true;
} catch (IOException e) {
Log.w(TAG, e);
@@ -281,14 +333,48 @@ public class ContactSelectionListFragment extends Fragment
private class ListClickListener implements ContactSelectionListAdapter.ItemClickListener {
@Override
public void onItemClick(ContactSelectionListItem contact) {
if (!isMulti() || !selectedContacts.contains(contact.getNumber())) {
selectedContacts.add(contact.getNumber());
contact.setChecked(true);
if (onContactSelectedListener != null) onContactSelectedListener.onContactSelected(contact.getNumber());
SelectedContact selectedContact = contact.isUsernameType() ? SelectedContact.forUsername(contact.getRecipientId().orNull(), contact.getNumber())
: SelectedContact.forPhone(contact.getRecipientId().orNull(), contact.getNumber());
if (!isMulti() || !selectedContacts.contains(selectedContact)) {
if (contact.isUsernameType()) {
AlertDialog loadingDialog = SimpleProgressDialog.show(requireContext());
SimpleTask.run(getViewLifecycleOwner().getLifecycle(), () -> {
return UsernameUtil.fetchUuidForUsername(requireContext(), contact.getNumber());
}, uuid -> {
loadingDialog.dismiss();
if (uuid.isPresent()) {
Recipient recipient = Recipient.externalUsername(requireContext(), uuid.get(), contact.getNumber());
selectedContacts.add(SelectedContact.forUsername(recipient.getId(), contact.getNumber()));
contact.setChecked(true);
if (onContactSelectedListener != null) {
onContactSelectedListener.onContactSelected(Optional.of(recipient.getId()), null);
}
} else {
new AlertDialog.Builder(requireContext())
.setTitle(R.string.ContactSelectionListFragment_username_not_found)
.setMessage(getString(R.string.ContactSelectionListFragment_s_is_not_a_signal_user, contact.getNumber()))
.setPositiveButton(R.string.ContactSelectionListFragment_okay, (dialog, which) -> dialog.dismiss())
.show();
}
});
} else {
selectedContacts.add(selectedContact);
contact.setChecked(true);
if (onContactSelectedListener != null) {
onContactSelectedListener.onContactSelected(contact.getRecipientId(), contact.getNumber());
}
}
} else {
selectedContacts.remove(contact.getNumber());
selectedContacts.remove(selectedContact);
contact.setChecked(false);
if (onContactSelectedListener != null) onContactSelectedListener.onContactDeselected(contact.getNumber());
if (onContactSelectedListener != null) {
onContactSelectedListener.onContactDeselected(contact.getRecipientId(), contact.getNumber());
}
}
}
}
@@ -302,8 +388,11 @@ public class ContactSelectionListFragment extends Fragment
}
public interface OnContactSelectedListener {
void onContactSelected(String number);
void onContactDeselected(String number);
void onContactSelected(Optional<RecipientId> recipientId, String number);
void onContactDeselected(Optional<RecipientId> recipientId, String number);
}
public interface InviteCallback {
void onInvite();
}
}

View File

@@ -36,15 +36,19 @@ import org.thoughtcrime.securesms.components.emoji.EmojiToggle;
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard;
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobs.MultiDeviceProfileKeyUpdateJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceProfileContentUpdateJob;
import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.profiles.ProfileMediaConstraints;
import org.thoughtcrime.securesms.profiles.SystemProfileUtil;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.BitmapDecodingException;
import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.DynamicLanguage;
@@ -147,7 +151,7 @@ public class CreateProfileActivity extends BaseActionBarActivity {
if (data != null && data.getBooleanExtra("delete", false)) {
avatarBytes = null;
avatar.setImageDrawable(new ResourceContactPhoto(R.drawable.ic_camera_alt_white_24dp).asDrawable(this, getResources().getColor(R.color.grey_400)));
avatar.setImageDrawable(new ResourceContactPhoto(R.drawable.ic_camera_solid_white_24).asDrawable(this, getResources().getColor(R.color.grey_400)));
} else {
AvatarSelection.circularCropImage(this, inputFile, outputFile, R.string.CropImageActivity_profile_avatar);
}
@@ -260,14 +264,14 @@ public class CreateProfileActivity extends BaseActionBarActivity {
}
private void initializeProfileAvatar(boolean excludeSystem) {
Address ourAddress = Address.fromSerialized(TextSecurePreferences.getLocalNumber(this));
RecipientId selfId = Recipient.self().getId();
if (AvatarHelper.getAvatarFile(this, ourAddress).exists() && AvatarHelper.getAvatarFile(this, ourAddress).length() > 0) {
if (AvatarHelper.getAvatarFile(this, selfId).exists() && AvatarHelper.getAvatarFile(this, selfId).length() > 0) {
new AsyncTask<Void, Void, byte[]>() {
@Override
protected byte[] doInBackground(Void... params) {
try {
return Util.readFully(AvatarHelper.getInputStreamFor(CreateProfileActivity.this, ourAddress));
return Util.readFully(AvatarHelper.getInputStreamFor(CreateProfileActivity.this, selfId));
} catch (IOException e) {
Log.w(TAG, e);
return null;
@@ -362,6 +366,7 @@ public class CreateProfileActivity extends BaseActionBarActivity {
try {
accountManager.setProfileName(profileKey, name);
TextSecurePreferences.setProfileName(context, name);
DatabaseFactory.getRecipientDatabase(context).setProfileName(Recipient.self().getId(), name);
} catch (IOException e) {
Log.w(TAG, e);
return false;
@@ -369,14 +374,15 @@ public class CreateProfileActivity extends BaseActionBarActivity {
try {
accountManager.setProfileAvatar(profileKey, avatar);
AvatarHelper.setAvatar(CreateProfileActivity.this, Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)), avatarBytes);
AvatarHelper.setAvatar(CreateProfileActivity.this, Recipient.self().getId(), avatarBytes);
TextSecurePreferences.setProfileAvatarId(CreateProfileActivity.this, new SecureRandom().nextInt());
} catch (IOException e) {
Log.w(TAG, e);
return false;
}
ApplicationContext.getInstance(context).getJobManager().add(new MultiDeviceProfileKeyUpdateJob());
ApplicationDependencies.getJobManager().add(new MultiDeviceProfileKeyUpdateJob());
ApplicationDependencies.getJobManager().add(new MultiDeviceProfileContentUpdateJob());
return true;
}

View File

@@ -149,7 +149,8 @@ public class DatabaseMigrationActivity extends PassphraseRequiredActionBarActivi
if (getIntent().hasExtra("next_intent")) {
startActivity((Intent)getIntent().getParcelableExtra("next_intent"));
} else {
startActivity(new Intent(this, ConversationListActivity.class));
// TODO [greyson] Navigation
startActivity(new Intent(this, MainActivity.class));
}
}

View File

@@ -16,9 +16,11 @@ import android.widget.Button;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
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.push.AccountManagerFactory;
@@ -61,6 +63,7 @@ public class DeviceActivity extends PassphraseRequiredActionBarActivity
@Override
public void onCreate(Bundle bundle, boolean ready) {
getSupportActionBar().setHomeAsUpIndicator(ContextCompat.getDrawable(this, R.drawable.ic_arrow_left_24));
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(R.string.AndroidManifest__linked_devices);
this.deviceAddFragment = new DeviceAddFragment();
@@ -175,7 +178,7 @@ public class DeviceActivity extends PassphraseRequiredActionBarActivity
try {
Context context = DeviceActivity.this;
SignalServiceAccountManager accountManager = AccountManagerFactory.createManager(context);
SignalServiceAccountManager accountManager = ApplicationDependencies.getSignalServiceAccountManager();
String verificationCode = accountManager.getNewDeviceVerificationCode();
String ephemeralId = uri.getQueryParameter("uuid");
String publicKeyEncoded = uri.getQueryParameter("pub_key");

View File

@@ -1,5 +1,6 @@
package org.thoughtcrime.securesms;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
@@ -13,7 +14,6 @@ import androidx.appcompat.app.AlertDialog;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.devicelist.Device;
import org.thoughtcrime.securesms.jobs.RefreshUnidentifiedDeliveryAbilityJob;
import org.thoughtcrime.securesms.logging.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -162,6 +162,7 @@ public class DeviceListFragment extends ListFragment
builder.show();
}
@SuppressLint("StaticFieldLeak")
private void handleDisconnectDevice(final long deviceId) {
new ProgressDialogAsyncTask<Void, Void, Void>(getActivity(),
R.string.DeviceListActivity_unlinking_device_no_ellipsis,
@@ -171,10 +172,6 @@ public class DeviceListFragment extends ListFragment
protected Void doInBackground(Void... params) {
try {
accountManager.removeDevice(deviceId);
ApplicationContext.getInstance(getContext())
.getJobManager()
.add(new RefreshUnidentifiedDeliveryAbilityJob());
} catch (IOException e) {
Log.w(TAG, e);
Toast.makeText(getActivity(), R.string.DeviceListActivity_network_failed, Toast.LENGTH_LONG).show();

View File

@@ -18,8 +18,12 @@ import com.melnykov.fab.FloatingActionButton;
import com.nineoldandroids.animation.ArgbEvaluator;
import org.thoughtcrime.securesms.IntroPagerAdapter.IntroPage;
import org.thoughtcrime.securesms.database.model.Sticker;
import org.thoughtcrime.securesms.experienceupgrades.StickersIntroFragment;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
@@ -29,11 +33,17 @@ import org.whispersystems.libsignal.util.guava.Optional;
import java.util.Collections;
import java.util.List;
public class ExperienceUpgradeActivity extends BaseActionBarActivity implements TypingIndicatorIntroFragment.Controller, LinkPreviewsIntroFragment.Controller {
public class ExperienceUpgradeActivity extends BaseActionBarActivity
implements TypingIndicatorIntroFragment.Controller,
LinkPreviewsIntroFragment.Controller,
StickersIntroFragment.Controller
{
private static final String TAG = ExperienceUpgradeActivity.class.getSimpleName();
private static final String DISMISS_ACTION = "org.thoughtcrime.securesms.ExperienceUpgradeActivity.DISMISS_ACTION";
private static final int NOTIFICATION_ID = 1339;
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
private enum ExperienceUpgrade {
SIGNAL_REBRANDING(157,
new IntroPage(0xFF2090EA,
@@ -86,8 +96,15 @@ public class ExperienceUpgradeActivity extends BaseActionBarActivity implements
R.string.ExperienceUpgradeActivity_introducing_link_previews,
R.string.ExperienceUpgradeActivity_optional_link_previews_are_now_supported,
R.string.ExperienceUpgradeActivity_optional_link_previews_are_now_supported,
null,
true);
null,
true),
STICKERS(580,
new IntroPage(0xFF2090EA, StickersIntroFragment.newInstance()),
R.string.ExperienceUpgradeActivity_introducing_stickers,
R.string.ExperienceUpgradeActivity_why_use_words_when_you_can_use_stickers,
R.string.ExperienceUpgradeActivity_why_use_words_when_you_can_use_stickers,
null,
true);
private int version;
private List<IntroPage> pages;
@@ -157,7 +174,7 @@ public class ExperienceUpgradeActivity extends BaseActionBarActivity implements
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStatusBarColor(getResources().getColor(R.color.signal_primary_dark));
dynamicTheme.onCreate(this);
final Optional<ExperienceUpgrade> upgrade = getExperienceUpgrade(this);
if (!upgrade.isPresent()) {
@@ -182,6 +199,12 @@ public class ExperienceUpgradeActivity extends BaseActionBarActivity implements
ServiceUtil.getNotificationManager(this).cancel(NOTIFICATION_ID);
}
@Override
protected void onResume() {
super.onResume();
dynamicTheme.onResume(this);
}
private void onContinue(Optional<ExperienceUpgrade> seenUpgrade) {
ServiceUtil.getNotificationManager(this).cancel(NOTIFICATION_ID);
int latestVersion = seenUpgrade.isPresent() ? seenUpgrade.get().getVersion()
@@ -189,7 +212,8 @@ public class ExperienceUpgradeActivity extends BaseActionBarActivity implements
TextSecurePreferences.setLastExperienceVersionCode(this, latestVersion);
if (seenUpgrade.isPresent() && seenUpgrade.get().nextIntent != null) {
Intent intent = new Intent(this, seenUpgrade.get().nextIntent);
Intent nextIntent = new Intent(this, ConversationListActivity.class);
// TODO [greyson] Navigation
Intent nextIntent = new Intent(this, MainActivity.class);
intent.putExtra("next_intent", nextIntent);
startActivity(intent);
} else {
@@ -231,29 +255,9 @@ public class ExperienceUpgradeActivity extends BaseActionBarActivity implements
onContinue(Optional.of(ExperienceUpgrade.LINK_PREVIEWS));
}
private final class OnPageChangeListener implements ViewPager.OnPageChangeListener {
private final ArgbEvaluator evaluator = new ArgbEvaluator();
private final ExperienceUpgrade upgrade;
public OnPageChangeListener(ExperienceUpgrade upgrade) {
this.upgrade = upgrade;
}
@Override
public void onPageSelected(int position) {}
@Override
public void onPageScrollStateChanged(int state) {}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
final int nextPosition = (position + 1) % upgrade.getPages().size();
final int color = (Integer)evaluator.evaluate(positionOffset,
upgrade.getPage(position).backgroundColor,
upgrade.getPage(nextPosition).backgroundColor);
getWindow().setBackgroundDrawable(new ColorDrawable(color));
}
@Override
public void onStickersFinished() {
onContinue(Optional.of(ExperienceUpgrade.STICKERS));
}
public static class AppUpgradeReceiver extends BroadcastReceiver {

View File

@@ -20,11 +20,13 @@ package org.thoughtcrime.securesms;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import android.text.TextUtils;
import org.thoughtcrime.securesms.avatar.AvatarSelection;
@@ -50,7 +52,6 @@ import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
import org.thoughtcrime.securesms.contacts.RecipientsEditor;
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
@@ -60,6 +61,7 @@ import org.thoughtcrime.securesms.groups.GroupManager;
import org.thoughtcrime.securesms.groups.GroupManager.GroupActionResult;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
@@ -90,7 +92,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
private final static String TAG = GroupCreateActivity.class.getSimpleName();
public static final String GROUP_ADDRESS_EXTRA = "group_recipient";
public static final String GROUP_ID_EXTRA = "group_id";
public static final String GROUP_THREAD_EXTRA = "group_thread";
private final DynamicTheme dynamicTheme = new DynamicTheme();
@@ -117,7 +119,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
protected void onCreate(Bundle state, boolean ready) {
setContentView(R.layout.group_create_activity);
//noinspection ConstantConditions
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
initializeAppBar();
initializeResources();
initializeExistingGroup();
}
@@ -176,6 +178,12 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
addSelectedContacts(recipients.toArray(new Recipient[recipients.size()]));
}
private void initializeAppBar() {
Drawable upIcon = ContextCompat.getDrawable(this, R.drawable.ic_arrow_left_24);
getSupportActionBar().setHomeAsUpIndicator(upIcon);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
private void initializeResources() {
RecipientsEditor recipientsEditor = ViewUtil.findById(this, R.id.recipients_text);
PushRecipientsPanel recipientsPanel = ViewUtil.findById(this, R.id.recipients);
@@ -189,15 +197,15 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
recipientsEditor.setHint(R.string.recipients_panel__add_members);
recipientsPanel.setPanelChangeListener(this);
findViewById(R.id.contacts_button).setOnClickListener(new AddRecipientButtonListener());
avatar.setImageDrawable(new ResourceContactPhoto(R.drawable.ic_group_white_24dp).asDrawable(this, ContactColors.UNKNOWN_COLOR.toConversationColor(this)));
avatar.setImageDrawable(new ResourceContactPhoto(R.drawable.ic_group_outline_40, R.drawable.ic_group_outline_20).asDrawable(this, ContactColors.UNKNOWN_COLOR.toConversationColor(this)));
avatar.setOnClickListener(view -> AvatarSelection.startAvatarSelection(this, false, false));
}
private void initializeExistingGroup() {
final Address groupAddress = getIntent().getParcelableExtra(GROUP_ADDRESS_EXTRA);
final String groupId = getIntent().getStringExtra(GROUP_ID_EXTRA);
if (groupAddress != null) {
new FillExistingGroupInfoAsyncTask(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, groupAddress.toGroupString());
if (groupId != null) {
new FillExistingGroupInfoAsyncTask(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, groupId);
}
}
@@ -260,7 +268,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
Intent intent = new Intent(this, ConversationActivity.class);
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT);
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
intent.putExtra(ConversationActivity.RECIPIENT_EXTRA, recipient.getId());
startActivity(intent);
finish();
}
@@ -283,14 +291,13 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
switch (reqCode) {
case PICK_CONTACT:
List<String> selected = data.getStringArrayListExtra("contacts");
for (String contact : selected) {
Address address = Address.fromExternal(this, contact);
Recipient recipient = Recipient.from(this, address, false);
List<RecipientId> selected = data.getParcelableArrayListExtra(PushContactSelectionActivity.KEY_SELECTED_RECIPIENTS);
for (RecipientId contact : selected) {
Recipient recipient = Recipient.resolved(contact);
addSelectedContacts(recipient);
}
break;
case AvatarSelection.REQUEST_CODE_AVATAR:
@@ -338,16 +345,17 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
@Override
protected GroupActionResult doInBackground(Void... avoid) {
List<Address> memberAddresses = new LinkedList<>();
List<RecipientId> memberAddresses = new LinkedList<>();
for (Recipient recipient : members) {
memberAddresses.add(recipient.getAddress());
memberAddresses.add(recipient.getId());
}
memberAddresses.add(Address.fromSerialized(TextSecurePreferences.getLocalNumber(activity)));
memberAddresses.add(Recipient.self().getId());
String groupId = DatabaseFactory.getGroupDatabase(activity).getOrCreateGroupForMembers(memberAddresses, true);
Recipient groupRecipient = Recipient.from(activity, Address.fromSerialized(groupId), true);
long threadId = DatabaseFactory.getThreadDatabase(activity).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.DEFAULT);
String groupId = DatabaseFactory.getGroupDatabase(activity).getOrCreateGroupForMembers(memberAddresses, true);
RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(activity).getOrInsertFromGroupId(groupId);
Recipient groupRecipient = Recipient.resolved(groupRecipientId);
long threadId = DatabaseFactory.getThreadDatabase(activity).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.DEFAULT);
return new GroupActionResult(groupRecipient, threadId);
}
@@ -450,7 +458,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
if (!activity.isFinishing()) {
Intent intent = activity.getIntent();
intent.putExtra(GROUP_THREAD_EXTRA, result.get().getThreadId());
intent.putExtra(GROUP_ADDRESS_EXTRA, result.get().getGroupRecipient().getAddress());
intent.putExtra(GROUP_ID_EXTRA, result.get().getGroupRecipient().requireGroupId());
activity.setResult(RESULT_OK, intent);
activity.finish();
}
@@ -492,8 +500,8 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
if (failIfNotPush && !isPush) {
results.add(new Result(null, false, activity.getString(R.string.GroupCreateActivity_cannot_add_non_push_to_existing_group,
recipient.toShortString())));
} else if (TextUtils.equals(TextSecurePreferences.getLocalNumber(activity), recipient.getAddress().serialize())) {
recipient.toShortString(activity))));
} else if (TextUtils.equals(TextSecurePreferences.getLocalNumber(activity), recipient.getE164().or(""))) {
results.add(new Result(null, false, activity.getString(R.string.GroupCreateActivity_youre_already_in_the_group)));
} else {
results.add(new Result(recipient, isPush, null));

View File

@@ -10,6 +10,7 @@ import android.text.TextUtils;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientExporter;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.Util;
import java.util.LinkedList;
@@ -32,7 +33,7 @@ public class GroupMembersDialog extends AsyncTask<Void, Void, List<Recipient>> {
@Override
protected List<Recipient> doInBackground(Void... params) {
return DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipient.getAddress().toGroupString(), true);
return DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipient.requireGroupId(), true);
}
@Override
@@ -66,7 +67,7 @@ public class GroupMembersDialog extends AsyncTask<Void, Void, List<Recipient>> {
if (recipient.getContactUri() != null) {
Intent intent = new Intent(context, RecipientPreferenceActivity.class);
intent.putExtra(RecipientPreferenceActivity.ADDRESS_EXTRA, recipient.getAddress());
intent.putExtra(RecipientPreferenceActivity.RECIPIENT_ID, recipient.getId());
context.startActivity(intent);
} else {
@@ -90,7 +91,7 @@ public class GroupMembersDialog extends AsyncTask<Void, Void, List<Recipient>> {
public GroupMembers(List<Recipient> recipients) {
for (Recipient recipient : recipients) {
if (isLocalNumber(recipient)) {
if (recipient.isLocalNumber()) {
members.push(recipient);
} else {
members.add(recipient);
@@ -102,15 +103,10 @@ public class GroupMembersDialog extends AsyncTask<Void, Void, List<Recipient>> {
List<String> recipientStrings = new LinkedList<>();
for (Recipient recipient : members) {
if (isLocalNumber(recipient)) {
if (recipient.isLocalNumber()) {
recipientStrings.add(context.getString(R.string.GroupMembersDialog_me));
} else {
String name = recipient.toShortString();
if (recipient.getName() == null && !TextUtils.isEmpty(recipient.getProfileName())) {
name += " ~" + recipient.getProfileName();
}
String name = getRecipientName(recipient);
recipientStrings.add(name);
}
}
@@ -118,12 +114,20 @@ public class GroupMembersDialog extends AsyncTask<Void, Void, List<Recipient>> {
return recipientStrings.toArray(new String[members.size()]);
}
private String getRecipientName(Recipient recipient) {
if (FeatureFlags.PROFILE_DISPLAY) return recipient.getDisplayName(context);
String name = recipient.toShortString(context);
if (recipient.getName(context) == null && !TextUtils.isEmpty(recipient.getProfileName())) {
name += " ~" + recipient.getProfileName();
}
return name;
}
public Recipient get(int index) {
return members.get(index);
}
private boolean isLocalNumber(Recipient recipient) {
return Util.isOwnNumber(context, recipient.getAddress());
}
}
}

View File

@@ -0,0 +1,115 @@
package org.thoughtcrime.securesms;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.PushDatabase;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobmanager.JobManager;
import org.thoughtcrime.securesms.jobs.PushDecryptMessageJob;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
import java.io.Closeable;
import java.util.Locale;
import java.util.concurrent.locks.ReentrantLock;
/**
* The central entry point for all envelopes that have been retrieved. Envelopes must be processed
* here to guarantee proper ordering.
*/
public class IncomingMessageProcessor {
private static final String TAG = Log.tag(IncomingMessageProcessor.class);
private final Context context;
private final ReentrantLock lock;
public IncomingMessageProcessor(@NonNull Context context) {
this.context = context;
this.lock = new ReentrantLock();
}
/**
* @return An instance of a Processor that will allow you to process messages in a thread safe
* way. Must be closed.
*/
public Processor acquire() {
lock.lock();
Thread current = Thread.currentThread();
Log.d(TAG, "Lock acquired by thread " + current.getId() + " (" + current.getName() + ")");
return new Processor(context);
}
private void release() {
Thread current = Thread.currentThread();
Log.d(TAG, "Lock about to be released by thread " + current.getId() + " (" + current.getName() + ")");
lock.unlock();
}
public class Processor implements Closeable {
private final Context context;
private final PushDatabase pushDatabase;
private final MmsSmsDatabase mmsSmsDatabase;
private final JobManager jobManager;
private Processor(@NonNull Context context) {
this.context = context;
this.pushDatabase = DatabaseFactory.getPushDatabase(context);
this.mmsSmsDatabase = DatabaseFactory.getMmsSmsDatabase(context);
this.jobManager = ApplicationDependencies.getJobManager();
}
/**
* @return The id of the {@link PushDecryptMessageJob} that was scheduled to process the message, if
* one was created. Otherwise null.
*/
public @Nullable String processEnvelope(@NonNull SignalServiceEnvelope envelope) {
if (envelope.hasSource()) {
Recipient.externalPush(context, envelope.getSourceAddress());
}
if (envelope.isReceipt()) {
processReceipt(envelope);
return null;
} else if (envelope.isPreKeySignalMessage() || envelope.isSignalMessage() || envelope.isUnidentifiedSender()) {
return processMessage(envelope);
} else {
Log.w(TAG, "Received envelope of unknown type: " + envelope.getType());
return null;
}
}
private @NonNull String processMessage(@NonNull SignalServiceEnvelope envelope) {
Log.i(TAG, "Received message. Inserting in PushDatabase.");
long id = pushDatabase.insert(envelope);
PushDecryptMessageJob job = new PushDecryptMessageJob(context, id);
jobManager.add(job);
return job.getId();
}
private void processReceipt(@NonNull SignalServiceEnvelope envelope) {
Log.i(TAG, String.format(Locale.ENGLISH, "Received receipt: (XXXXX, %d)", envelope.getTimestamp()));
mmsSmsDatabase.incrementDeliveryReceiptCount(new SyncMessageId(Recipient.externalPush(context, envelope.getSourceAddress()).getId(), envelope.getTimestamp()),
System.currentTimeMillis());
}
@Override
public void close() {
release();
}
}
}

View File

@@ -1,40 +1,46 @@
package org.thoughtcrime.securesms;
import android.animation.Animator;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.graphics.PorterDuff;
import android.os.AsyncTask;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.AnimRes;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import androidx.appcompat.app.AlertDialog;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewAnimationUtils;
import android.view.ViewGroup;
import android.view.ViewTreeObserver.OnPreDrawListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.annotation.AnimRes;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.components.ContactFilterToolbar;
import org.thoughtcrime.securesms.components.ContactFilterToolbar.OnFilterChangedListener;
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.contacts.SelectedContact;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.util.DynamicNoActionBarInviteTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.ThemeUtil;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.WindowUtil;
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture.Listener;
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
import org.whispersystems.libsignal.util.guava.Optional;
import java.util.concurrent.ExecutionException;
@@ -46,7 +52,14 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
private Button smsSendButton;
private Animation slideInAnimation;
private Animation slideOutAnimation;
private ImageView heart;
private DynamicTheme dynamicTheme = new DynamicNoActionBarInviteTheme();
private Toolbar primaryToolbar;
@Override
protected void onPreCreate() {
super.onPreCreate();
dynamicTheme.onCreate(this);
}
@Override
protected void onCreate(Bundle savedInstanceState, boolean ready) {
@@ -55,12 +68,27 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
getIntent().putExtra(ContactSelectionListFragment.REFRESHABLE, false);
setContentView(R.layout.invite_activity);
assert getSupportActionBar() != null;
getSupportActionBar().setTitle(R.string.AndroidManifest__invite_friends);
initializeAppBar();
initializeResources();
}
@Override
protected void onResume() {
super.onResume();
dynamicTheme.onResume(this);
}
private void initializeAppBar() {
primaryToolbar = findViewById(R.id.toolbar);
setSupportActionBar(primaryToolbar);
assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(R.string.AndroidManifest__invite_friends);
}
private void initializeResources() {
slideInAnimation = loadAnimation(R.anim.slide_from_bottom);
slideOutAnimation = loadAnimation(R.anim.slide_to_bottom);
@@ -73,22 +101,18 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
inviteText = ViewUtil.findById(this, R.id.invite_text);
smsSendFrame = ViewUtil.findById(this, R.id.sms_send_frame);
smsSendButton = ViewUtil.findById(this, R.id.send_sms_button);
heart = ViewUtil.findById(this, R.id.heart);
contactsFragment = (ContactSelectionListFragment)getSupportFragmentManager().findFragmentById(R.id.contact_selection_list_fragment);
inviteText.setText(getString(R.string.InviteActivity_lets_switch_to_signal, getString(R.string.install_url)));
updateSmsButtonText();
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
heart.getViewTreeObserver().addOnPreDrawListener(new HeartPreDrawListener());
}
contactsFragment.setOnContactSelectedListener(this);
shareButton.setOnClickListener(new ShareClickListener());
smsButton.setOnClickListener(new SmsClickListener());
smsCancelButton.setOnClickListener(new SmsCancelClickListener());
smsSendButton.setOnClickListener(new SmsSendClickListener());
contactFilter.setOnFilterChangedListener(new ContactFilterChangedListener());
contactFilter.setNavigationIcon(R.drawable.ic_search_white_24dp);
contactFilter.setNavigationIcon(R.drawable.ic_search_conversation_24);
}
private Animation loadAnimation(@AnimRes int animResId) {
@@ -98,12 +122,12 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
}
@Override
public void onContactSelected(String number) {
public void onContactSelected(Optional<RecipientId> recipientId, String number) {
updateSmsButtonText();
}
@Override
public void onContactDeselected(String number) {
public void onContactDeselected(Optional<RecipientId> recipientId, String number) {
updateSmsButtonText();
}
@@ -111,7 +135,7 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
new SendSmsInvitesAsyncTask(this, inviteText.getText().toString())
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
contactsFragment.getSelectedContacts()
.toArray(new String[contactsFragment.getSelectedContacts().size()]));
.toArray(new SelectedContact[contactsFragment.getSelectedContacts().size()]));
}
private void updateSmsButtonText() {
@@ -130,11 +154,42 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
}
private void cancelSmsSelection() {
setPrimaryColorsToolbarNormal();
contactsFragment.reset();
updateSmsButtonText();
ViewUtil.animateOut(smsSendFrame, slideOutAnimation, View.GONE);
}
private void setPrimaryColorsToolbarNormal() {
primaryToolbar.setBackgroundColor(0);
primaryToolbar.getNavigationIcon().setColorFilter(null);
primaryToolbar.setTitleTextColor(ThemeUtil.getThemedColor(this, R.attr.title_text_color_primary));
if (Build.VERSION.SDK_INT >= 23) {
getWindow().setStatusBarColor(ThemeUtil.getThemedColor(this, android.R.attr.statusBarColor));
getWindow().setNavigationBarColor(ThemeUtil.getThemedColor(this, android.R.attr.navigationBarColor));
WindowUtil.setLightStatusBarFromTheme(this);
}
WindowUtil.setLightNavigationBarFromTheme(this);
}
private void setPrimaryColorsToolbarForSms() {
primaryToolbar.setBackgroundColor(ContextCompat.getColor(this, R.color.signal_primary));
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));
if (Build.VERSION.SDK_INT >= 23) {
getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.signal_primary));
WindowUtil.clearLightStatusBar(getWindow());
}
if (Build.VERSION.SDK_INT >= 27) {
getWindow().setNavigationBarColor(ContextCompat.getColor(this, R.color.signal_primary));
WindowUtil.clearLightNavigationBar(getWindow());
}
}
private class ShareClickListener implements OnClickListener {
@Override
public void onClick(View v) {
@@ -153,6 +208,7 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
private class SmsClickListener implements OnClickListener {
@Override
public void onClick(View v) {
setPrimaryColorsToolbarForSms();
ViewUtil.animateIn(smsSendFrame, slideInAnimation);
}
}
@@ -185,25 +241,8 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
}
}
private class HeartPreDrawListener implements OnPreDrawListener {
@Override
@TargetApi(VERSION_CODES.LOLLIPOP)
public boolean onPreDraw() {
heart.getViewTreeObserver().removeOnPreDrawListener(this);
final int w = heart.getWidth();
final int h = heart.getHeight();
Animator reveal = ViewAnimationUtils.createCircularReveal(heart,
w / 2, h,
0, (float)Math.sqrt(h*h + (w*w/4)));
reveal.setInterpolator(new FastOutSlowInInterpolator());
reveal.setDuration(800);
reveal.start();
return false;
}
}
@SuppressLint("StaticFieldLeak")
private class SendSmsInvitesAsyncTask extends ProgressDialogAsyncTask<String,Void,Void> {
private class SendSmsInvitesAsyncTask extends ProgressDialogAsyncTask<SelectedContact,Void,Void> {
private final String message;
SendSmsInvitesAsyncTask(Context context, String message) {
@@ -212,18 +251,19 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
}
@Override
protected Void doInBackground(String... numbers) {
protected Void doInBackground(SelectedContact... contacts) {
final Context context = getContext();
if (context == null) return null;
for (String number : numbers) {
Recipient recipient = Recipient.from(context, Address.fromExternal(context, number), false);
int subscriptionId = recipient.getDefaultSubscriptionId().or(-1);
for (SelectedContact contact : contacts) {
RecipientId recipientId = contact.getOrCreateRecipientId(context);
Recipient recipient = Recipient.resolved(recipientId);
int subscriptionId = recipient.getDefaultSubscriptionId().or(-1);
MessageSender.send(context, new OutgoingTextMessage(recipient, message, subscriptionId), -1L, true, null);
if (recipient.getContactUri() != null) {
DatabaseFactory.getRecipientDatabase(context).setSeenInviteReminder(recipient, true);
DatabaseFactory.getRecipientDatabase(context).setHasSentInvite(recipient.getId());
}
}

View File

@@ -9,6 +9,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
@@ -46,12 +47,10 @@ public class LinkPreviewsIntroFragment extends Fragment {
View view = inflater.inflate(R.layout.experience_upgrade_link_previews_fragment, container, false);
view.findViewById(R.id.experience_ok_button).setOnClickListener(v -> {
ApplicationContext.getInstance(requireContext())
.getJobManager()
.add(new MultiDeviceConfigurationUpdateJob(TextSecurePreferences.isReadReceiptsEnabled(requireContext()),
TextSecurePreferences.isTypingIndicatorsEnabled(requireContext()),
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(requireContext()),
TextSecurePreferences.isLinkPreviewsEnabled(requireContext())));
ApplicationDependencies.getJobManager().add(new MultiDeviceConfigurationUpdateJob(TextSecurePreferences.isReadReceiptsEnabled(requireContext()),
TextSecurePreferences.isTypingIndicatorsEnabled(requireContext()),
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(requireContext()),
TextSecurePreferences.isLinkPreviewsEnabled(requireContext())));
controller.onLinkPreviewsFinished();
});

View File

@@ -0,0 +1,45 @@
package org.thoughtcrime.securesms;
import android.os.Bundle;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
public class MainActivity extends PassphraseRequiredActionBarActivity {
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
private final MainNavigator navigator = new MainNavigator(this);
@Override
protected void onCreate(Bundle savedInstanceState, boolean ready) {
super.onCreate(savedInstanceState, ready);
setContentView(R.layout.main_activity);
navigator.onCreate(savedInstanceState);
}
@Override
protected void onPreCreate() {
super.onPreCreate();
dynamicTheme.onCreate(this);
}
@Override
protected void onResume() {
super.onResume();
dynamicTheme.onResume(this);
}
@Override
public void onBackPressed() {
if (!navigator.onBackPressed()) {
super.onBackPressed();
}
}
public @NonNull MainNavigator getNavigator() {
return navigator;
}
}

View File

@@ -0,0 +1,22 @@
package org.thoughtcrime.securesms;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
public class MainFragment extends Fragment {
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (!(requireActivity() instanceof MainActivity)) {
throw new IllegalStateException("Can only be used inside of MainActivity!");
}
}
protected @NonNull MainNavigator getNavigator() {
return MainNavigator.get(requireActivity());
}
}

View File

@@ -0,0 +1,104 @@
package org.thoughtcrime.securesms;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import org.thoughtcrime.securesms.conversation.ConversationActivity;
import org.thoughtcrime.securesms.conversationlist.ConversationListArchiveFragment;
import org.thoughtcrime.securesms.conversationlist.ConversationListFragment;
import org.thoughtcrime.securesms.insights.InsightsLauncher;
import org.thoughtcrime.securesms.recipients.RecipientId;
public class MainNavigator {
private final MainActivity activity;
public MainNavigator(@NonNull MainActivity activity) {
this.activity = activity;
}
public static MainNavigator get(@NonNull Activity activity) {
if (!(activity instanceof MainActivity)) {
throw new IllegalArgumentException("Activity must be an instance of MainActivity!");
}
return ((MainActivity) activity).getNavigator();
}
public void onCreate(@Nullable Bundle savedInstanceState) {
if (savedInstanceState != null) {
return;
}
getFragmentManager().beginTransaction()
.add(R.id.fragment_container, ConversationListFragment.newInstance())
.commit();
}
/**
* @return True if the back pressed was handled in our own custom way, false if it should be given
* to the system to do the default behavior.
*/
public boolean onBackPressed() {
Fragment fragment = getFragmentManager().findFragmentById(R.id.fragment_container);
if (fragment instanceof BackHandler) {
return ((BackHandler) fragment).onBackPressed();
}
return false;
}
public void goToConversation(@NonNull RecipientId recipientId, long threadId, int distributionType, long lastSeen, int startingPosition) {
Intent intent = ConversationActivity.buildIntent(activity, recipientId, threadId, distributionType, lastSeen, startingPosition);
activity.startActivity(intent);
activity.overridePendingTransition(R.anim.slide_from_end, R.anim.fade_scale_out);
}
public void goToAppSettings() {
Intent intent = new Intent(activity, ApplicationPreferencesActivity.class);
activity.startActivity(intent);
}
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)
.replace(R.id.fragment_container, ConversationListArchiveFragment.newInstance())
.addToBackStack(null)
.commit();
}
public void goToGroupCreation() {
Intent intent = new Intent(activity, GroupCreateActivity.class);
activity.startActivity(intent);
}
public void goToInvite() {
Intent intent = new Intent(activity, InviteActivity.class);
activity.startActivity(intent);
}
public void goToInsights() {
InsightsLauncher.showInsightsDashboard(activity.getSupportFragmentManager());
}
private @NonNull FragmentManager getFragmentManager() {
return activity.getSupportFragmentManager();
}
public interface BackHandler {
/**
* @return True if the back pressed was handled in our own custom way, false if it should be given
* to the system to do the default behavior.
*/
boolean onBackPressed();
}
}

View File

@@ -29,6 +29,7 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;
@@ -37,6 +38,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.util.Pair;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
@@ -50,23 +52,22 @@ import androidx.viewpager.widget.ViewPager;
import org.thoughtcrime.securesms.animation.DepthPageTransformer;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.components.viewpager.ExtendedOnPageChangedListener;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.MediaDatabase;
import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
import org.thoughtcrime.securesms.database.loaders.PagingMediaLoader;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mediaoverview.MediaOverviewActivity;
import org.thoughtcrime.securesms.mediapreview.MediaPreviewFragment;
import org.thoughtcrime.securesms.mediapreview.MediaPreviewViewModel;
import org.thoughtcrime.securesms.mediapreview.MediaRailAdapter;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.AttachmentUtil;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.SaveAttachmentTask;
import org.thoughtcrime.securesms.util.SaveAttachmentTask.Attachment;
import org.thoughtcrime.securesms.util.Util;
import java.util.HashMap;
import java.util.Locale;
@@ -76,20 +77,23 @@ import java.util.Map;
* Activity for displaying media attachments in-app
*/
public final class MediaPreviewActivity extends PassphraseRequiredActionBarActivity
implements RecipientModifiedListener,
LoaderManager.LoaderCallbacks<Pair<Cursor, Integer>>,
implements LoaderManager.LoaderCallbacks<Pair<Cursor, Integer>>,
MediaRailAdapter.RailItemListener,
MediaPreviewFragment.Events
{
private final static String TAG = MediaPreviewActivity.class.getSimpleName();
public static final String ADDRESS_EXTRA = "address";
private static final int NOT_IN_A_THREAD = -2;
public static final String THREAD_ID_EXTRA = "thread_id";
public static final String DATE_EXTRA = "date";
public static final String SIZE_EXTRA = "size";
public static final String CAPTION_EXTRA = "caption";
public static final String OUTGOING_EXTRA = "outgoing";
public static final String LEFT_IS_RECENT_EXTRA = "left_is_recent";
public static final String HIDE_ALL_MEDIA_EXTRA = "came_from_all_media";
public static final String SHOW_THREAD_EXTRA = "show_thread";
public static final String SORTING_EXTRA = "sorting";
private ViewPager mediaPager;
private View detailsContainer;
@@ -102,27 +106,32 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
private String initialMediaType;
private long initialMediaSize;
private String initialCaption;
private Recipient conversationRecipient;
private boolean leftIsRecent;
private MediaPreviewViewModel viewModel;
private ViewPagerListener viewPagerListener;
private int restartItem = -1;
private int restartItem = -1;
private long threadId = NOT_IN_A_THREAD;
private boolean cameFromAllMedia;
private boolean showThread;
private MediaDatabase.Sorting sorting;
@SuppressWarnings("ConstantConditions")
@Override
protected void onCreate(Bundle bundle, boolean ready) {
this.setTheme(R.style.TextSecure_DarkTheme);
this.setTheme(R.style.TextSecure_MediaPreview);
setContentView(R.layout.media_preview_activity);
setSupportActionBar(findViewById(R.id.toolbar));
viewModel = ViewModelProviders.of(this).get(MediaPreviewViewModel.class);
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
showSystemUI();
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setContentView(R.layout.media_preview_activity);
initializeViews();
initializeResources();
@@ -134,11 +143,6 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
}
@Override
public void onModified(Recipient recipient) {
Util.runOnMain(this::initializeActionBar);
}
@Override
public void onRailItemClicked(int distanceFromActive) {
mediaPager.setCurrentItem(mediaPager.getCurrentItem() + distanceFromActive);
@@ -154,19 +158,45 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
MediaItem mediaItem = getCurrentMediaItem();
if (mediaItem != null) {
CharSequence relativeTimeSpan;
getSupportActionBar().setTitle(getTitleText(mediaItem));
getSupportActionBar().setSubtitle(getSubTitleText(mediaItem));
}
}
if (mediaItem.date > 0) {
relativeTimeSpan = DateUtils.getExtendedRelativeTimeSpanString(this, Locale.getDefault(), mediaItem.date);
} else {
relativeTimeSpan = getString(R.string.MediaPreviewActivity_draft);
private @NonNull String getTitleText(@NonNull MediaItem mediaItem) {
String from;
if (mediaItem.outgoing) from = getString(R.string.MediaPreviewActivity_you);
else if (mediaItem.recipient != null) from = mediaItem.recipient.toShortString(this);
else from = "";
if (showThread) {
String to = null;
Recipient threadRecipient = mediaItem.threadRecipient;
if (threadRecipient != null) {
if (mediaItem.outgoing || threadRecipient.isGroup()) {
if (threadRecipient.isLocalNumber()) {
from = getString(R.string.note_to_self);
} else {
to = threadRecipient.toShortString(this);
}
} else {
to = getString(R.string.MediaPreviewActivity_you);
}
}
if (mediaItem.outgoing) getSupportActionBar().setTitle(getString(R.string.MediaPreviewActivity_you));
else if (mediaItem.recipient != null) getSupportActionBar().setTitle(mediaItem.recipient.toShortString());
else getSupportActionBar().setTitle("");
return to != null ? getString(R.string.MediaPreviewActivity_s_to_s, from, to)
: from;
} else {
return from;
}
}
getSupportActionBar().setSubtitle(relativeTimeSpan);
private @NonNull String getSubTitleText(@NonNull MediaItem mediaItem) {
if (mediaItem.date > 0) {
return DateUtils.getExtendedRelativeTimeSpanString(this, Locale.getDefault(), mediaItem.date);
} else {
return getString(R.string.MediaPreviewActivity_draft);
}
}
@@ -208,23 +238,30 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
caption = findViewById(R.id.media_preview_caption);
captionContainer = findViewById(R.id.media_preview_caption_container);
playbackControlsContainer = findViewById(R.id.media_preview_playback_controls_container);
View toolbarLayout = findViewById(R.id.toolbar_layout);
anchorMarginsToBottomInsets(detailsContainer);
anchorMarginsToTopInsets(toolbarLayout);
showAndHideWithSystemUI(getWindow(), detailsContainer, toolbarLayout);
}
private void initializeResources() {
Address address = getIntent().getParcelableExtra(ADDRESS_EXTRA);
Intent intent = getIntent();
initialMediaUri = getIntent().getData();
initialMediaType = getIntent().getType();
initialMediaSize = getIntent().getLongExtra(SIZE_EXTRA, 0);
initialCaption = getIntent().getStringExtra(CAPTION_EXTRA);
leftIsRecent = getIntent().getBooleanExtra(LEFT_IS_RECENT_EXTRA, false);
threadId = intent.getLongExtra(THREAD_ID_EXTRA, NOT_IN_A_THREAD);
cameFromAllMedia = intent.getBooleanExtra(HIDE_ALL_MEDIA_EXTRA, false);
showThread = intent.getBooleanExtra(SHOW_THREAD_EXTRA, false);
sorting = MediaDatabase.Sorting.values()[intent.getIntExtra(SORTING_EXTRA, 0)];
initialMediaUri = intent.getData();
initialMediaType = intent.getType();
initialMediaSize = intent.getLongExtra(SIZE_EXTRA, 0);
initialCaption = intent.getStringExtra(CAPTION_EXTRA);
leftIsRecent = intent.getBooleanExtra(LEFT_IS_RECENT_EXTRA, false);
restartItem = -1;
if (address != null) {
conversationRecipient = Recipient.from(this, address, true);
} else {
conversationRecipient = null;
}
}
private void initializeObservers() {
@@ -233,6 +270,11 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
return;
}
if (!((MediaItemAdapter) mediaPager.getAdapter()).hasFragmentFor(mediaPager.getCurrentItem())) {
Log.d(TAG, "MediaItemAdapter wasn't ready. Posting again...");
viewModel.resubmitPreviewData();
}
View playbackControls = ((MediaItemAdapter) mediaPager.getAdapter()).getPlaybackControls(mediaPager.getCurrentItem());
if (previewData.getAlbumThumbnails().isEmpty() && previewData.getCaption() == null && playbackControls == null) {
@@ -269,7 +311,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
Log.i(TAG, "Loading Part URI: " + initialMediaUri);
if (conversationRecipient != null) {
if (isMediaInDb()) {
LoaderManager.getInstance(this).restartLoader(0, null, this);
} else {
mediaPager.setAdapter(new SingleItemPagerAdapter(getSupportFragmentManager(), initialMediaUri, initialMediaType, initialMediaSize));
@@ -292,9 +334,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
}
private void showOverview() {
Intent intent = new Intent(this, MediaOverviewActivity.class);
intent.putExtra(MediaOverviewActivity.ADDRESS_EXTRA, conversationRecipient.getAddress());
startActivity(intent);
startActivity(MediaOverviewActivity.forThread(this, threadId));
}
private void forward() {
@@ -372,6 +412,10 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
menu.findItem(R.id.delete).setVisible(false);
}
if (cameFromAllMedia) {
menu.findItem(R.id.media_preview__overview).setVisible(false);
}
return true;
}
@@ -391,7 +435,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
}
private boolean isMediaInDb() {
return conversationRecipient != null;
return threadId != NOT_IN_A_THREAD;
}
private @Nullable MediaItem getCurrentMediaItem() {
@@ -410,7 +454,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
@Override
public @NonNull Loader<Pair<Cursor, Integer>> onCreateLoader(int id, Bundle args) {
return new PagingMediaLoader(this, conversationRecipient, initialMediaUri, leftIsRecent);
return new PagingMediaLoader(this, threadId, initialMediaUri, leftIsRecent, sorting);
}
@Override
@@ -439,11 +483,36 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
@Override
public boolean singleTapOnMedia() {
detailsContainer.setVisibility(detailsContainer.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE);
toggleUiVisibility();
return true;
}
private void toggleUiVisibility() {
int systemUiVisibility = getWindow().getDecorView().getSystemUiVisibility();
if ((systemUiVisibility & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0) {
showSystemUI();
} else {
hideSystemUI();
}
}
private void hideSystemUI() {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_IMMERSIVE |
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_FULLSCREEN );
}
private void showSystemUI() {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN );
}
private class ViewPagerListener extends ExtendedOnPageChangedListener {
@Override
@@ -454,7 +523,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
if (adapter != null) {
MediaItem item = adapter.getMediaItemFor(position);
if (item.recipient != null) item.recipient.addListener(MediaPreviewActivity.this);
if (item.recipient != null) item.recipient.live().observe(MediaPreviewActivity.this, r -> initializeActionBar());
viewModel.setActiveAlbumRailItem(MediaPreviewActivity.this, position);
initializeActionBar();
}
@@ -467,7 +536,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
if (adapter != null) {
MediaItem item = adapter.getMediaItemFor(position);
if (item.recipient != null) item.recipient.removeListener(MediaPreviewActivity.this);
if (item.recipient != null) item.recipient.live().removeObservers(MediaPreviewActivity.this);
adapter.pause(position);
}
@@ -515,7 +584,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
@Override
public MediaItem getMediaItemFor(int position) {
return new MediaItem(null, null, uri, mediaType, -1, true);
return new MediaItem(null, null, null, uri, mediaType, -1, true);
}
@Override
@@ -532,6 +601,53 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
}
return null;
}
@Override
public boolean hasFragmentFor(int position) {
return mediaPreviewFragment != null;
}
}
private static void anchorMarginsToBottomInsets(@NonNull View viewToAnchor) {
ViewCompat.setOnApplyWindowInsetsListener(viewToAnchor, (view, insets) -> {
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
layoutParams.setMargins(insets.getSystemWindowInsetLeft(),
layoutParams.topMargin,
insets.getSystemWindowInsetRight(),
insets.getSystemWindowInsetBottom());
view.setLayoutParams(layoutParams);
return insets;
});
}
private static void anchorMarginsToTopInsets(@NonNull View viewToAnchor) {
ViewCompat.setOnApplyWindowInsetsListener(viewToAnchor, (view, insets) -> {
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
layoutParams.setMargins(insets.getSystemWindowInsetLeft(),
insets.getSystemWindowInsetTop(),
insets.getSystemWindowInsetRight(),
layoutParams.bottomMargin);
view.setLayoutParams(layoutParams);
return insets;
});
}
private static void showAndHideWithSystemUI(@NonNull Window window, @NonNull View... views) {
window.getDecorView().setOnSystemUiVisibilityChangeListener(visibility -> {
boolean hide = (visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
for (View view : views) {
view.animate()
.alpha(hide ? 0 : 1)
.start();
}
});
}
private static class CursorPagerAdapter extends FragmentStatePagerAdapter implements MediaItemAdapter {
@@ -602,12 +718,15 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
public MediaItem getMediaItemFor(int position) {
cursor.moveToPosition(getCursorPosition(position));
MediaRecord mediaRecord = MediaRecord.from(context, cursor);
Address address = mediaRecord.getAddress();
MediaRecord mediaRecord = MediaRecord.from(context, cursor);
RecipientId recipientId = mediaRecord.getRecipientId();
RecipientId threadRecipientId = mediaRecord.getThreadRecipientId();
if (mediaRecord.getAttachment().getDataUri() == null) throw new AssertionError();
return new MediaItem(address != null ? Recipient.from(context, address,true) : null,
return new MediaItem(Recipient.live(recipientId).get(),
Recipient.live(threadRecipientId).get(),
mediaRecord.getAttachment(),
mediaRecord.getAttachment().getDataUri(),
mediaRecord.getContentType(),
@@ -628,6 +747,11 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
return null;
}
@Override
public boolean hasFragmentFor(int position) {
return mediaFragments.containsKey(position);
}
private int getCursorPosition(int position) {
if (leftIsRecent) return position;
else return cursor.getCount() - 1 - position;
@@ -636,6 +760,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
private static class MediaItem {
private final @Nullable Recipient recipient;
private final @Nullable Recipient threadRecipient;
private final @Nullable DatabaseAttachment attachment;
private final @NonNull Uri uri;
private final @NonNull String type;
@@ -643,18 +768,20 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
private final boolean outgoing;
private MediaItem(@Nullable Recipient recipient,
@Nullable Recipient threadRecipient,
@Nullable DatabaseAttachment attachment,
@NonNull Uri uri,
@NonNull String type,
long date,
boolean outgoing)
{
this.recipient = recipient;
this.attachment = attachment;
this.uri = uri;
this.type = type;
this.date = date;
this.outgoing = outgoing;
this.recipient = recipient;
this.threadRecipient = threadRecipient;
this.attachment = attachment;
this.uri = uri;
this.type = type;
this.date = date;
this.outgoing = outgoing;
}
}
@@ -662,5 +789,6 @@ public final class MediaPreviewActivity extends PassphraseRequiredActionBarActiv
MediaItem getMediaItemFor(int position);
void pause(int position);
@Nullable View getPlaybackControls(int position);
boolean hasFragmentFor(int position);
}
}

View File

@@ -52,10 +52,11 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.LiveRecipient;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.DynamicDarkActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.ExpirationUtil;
@@ -73,14 +74,14 @@ import java.util.Locale;
/**
* @author Jake McGinty
*/
public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity implements LoaderCallbacks<Cursor>, RecipientModifiedListener {
public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity implements LoaderCallbacks<Cursor> {
private final static String TAG = MessageDetailsActivity.class.getSimpleName();
public final static String MESSAGE_ID_EXTRA = "message_id";
public final static String THREAD_ID_EXTRA = "thread_id";
public final static String IS_PUSH_GROUP_EXTRA = "is_push_group";
public final static String TYPE_EXTRA = "type";
public final static String ADDRESS_EXTRA = "address";
public static final String MESSAGE_ID_EXTRA = "message_id";
public static final String THREAD_ID_EXTRA = "thread_id";
public static final String IS_PUSH_GROUP_EXTRA = "is_push_group";
public static final String TYPE_EXTRA = "type";
public static final String RECIPIENT_EXTRA = "recipient_id";
private GlideRequests glideRequests;
private long threadId;
@@ -100,7 +101,7 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
private ListView recipientsList;
private LayoutInflater inflater;
private DynamicTheme dynamicTheme = new DynamicTheme();
private DynamicTheme dynamicTheme = new DynamicDarkActionBarTheme();
private DynamicLanguage dynamicLanguage = new DynamicLanguage();
private boolean running;
@@ -149,10 +150,10 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Recipient recipient = Recipient.from(this, getIntent().getParcelableExtra(ADDRESS_EXTRA), true);
recipient.addListener(this);
LiveRecipient recipient = Recipient.live(getIntent().getParcelableExtra(RECIPIENT_EXTRA));
recipient.observe(this, r -> setActionBarColor(r.getColor()));
setActionBarColor(recipient.getColor());
setActionBarColor(recipient.get().getColor());
}
private void setActionBarColor(MaterialColor color) {
@@ -164,11 +165,6 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
}
}
@Override
public void onModified(final Recipient recipient) {
Util.runOnMain(() -> setActionBarColor(recipient.getColor()));
}
private void initializeResources() {
inflater = LayoutInflater.from(this);
View header = inflater.inflate(R.layout.message_details_header, recipientsList, false);
@@ -366,20 +362,20 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
List<RecipientDeliveryStatus> recipients = new LinkedList<>();
if (!messageRecord.getRecipient().isGroupRecipient()) {
if (!messageRecord.getRecipient().isGroup()) {
recipients.add(new RecipientDeliveryStatus(messageRecord.getRecipient(), getStatusFor(messageRecord.getDeliveryReceiptCount(), messageRecord.getReadReceiptCount(), messageRecord.isPending()), messageRecord.isUnidentified(), -1));
} else {
List<GroupReceiptInfo> receiptInfoList = DatabaseFactory.getGroupReceiptDatabase(context).getGroupReceiptInfo(messageRecord.getId());
if (receiptInfoList.isEmpty()) {
List<Recipient> group = DatabaseFactory.getGroupDatabase(context).getGroupMembers(messageRecord.getRecipient().getAddress().toGroupString(), false);
List<Recipient> group = DatabaseFactory.getGroupDatabase(context).getGroupMembers(messageRecord.getRecipient().requireGroupId(), false);
for (Recipient recipient : group) {
recipients.add(new RecipientDeliveryStatus(recipient, RecipientDeliveryStatus.Status.UNKNOWN, false, -1));
}
} else {
for (GroupReceiptInfo info : receiptInfoList) {
recipients.add(new RecipientDeliveryStatus(Recipient.from(context, info.getAddress(), true),
recipients.add(new RecipientDeliveryStatus(Recipient.resolved(info.getRecipientId()),
getStatusFor(info.getStatus(), messageRecord.isPending(), messageRecord.isFailed()),
info.isUnidentified(),
info.getTimestamp()));

View File

@@ -11,7 +11,9 @@ import android.widget.BaseAdapter;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.Conversions;
import org.thoughtcrime.securesms.util.adapter.StableIdGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -19,11 +21,12 @@ import java.util.List;
class MessageDetailsRecipientAdapter extends BaseAdapter implements AbsListView.RecyclerListener {
private final Context context;
private final GlideRequests glideRequests;
private final MessageRecord record;
private final List<RecipientDeliveryStatus> members;
private final boolean isPushGroup;
private final Context context;
private final GlideRequests glideRequests;
private final MessageRecord record;
private final List<RecipientDeliveryStatus> members;
private final boolean isPushGroup;
private final StableIdGenerator<RecipientId> idGenerator;
MessageDetailsRecipientAdapter(@NonNull Context context, @NonNull GlideRequests glideRequests,
@NonNull MessageRecord record, @NonNull List<RecipientDeliveryStatus> members,
@@ -34,6 +37,7 @@ class MessageDetailsRecipientAdapter extends BaseAdapter implements AbsListView.
this.record = record;
this.isPushGroup = isPushGroup;
this.members = members;
this.idGenerator = new StableIdGenerator<>();
}
@Override
@@ -48,11 +52,7 @@ class MessageDetailsRecipientAdapter extends BaseAdapter implements AbsListView.
@Override
public long getItemId(int position) {
try {
return Conversions.byteArrayToLong(MessageDigest.getInstance("SHA1").digest(members.get(position).recipient.getAddress().serialize().getBytes()));
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
return idGenerator.getId(members.get(position).recipient.getId());
}
@Override

View File

@@ -25,6 +25,8 @@ import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.MessageDetailsRecipientAdapter.RecipientDeliveryStatus;
import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.components.DeliveryStatusView;
@@ -32,11 +34,11 @@ import org.thoughtcrime.securesms.components.FromTextView;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
/**
* A simple view to show the recipients of a message
@@ -44,7 +46,7 @@ import org.thoughtcrime.securesms.util.Util;
* @author Jake McGinty
*/
public class MessageRecipientListItem extends RelativeLayout
implements RecipientModifiedListener
implements RecipientForeverObserver
{
@SuppressWarnings("unused")
private final static String TAG = MessageRecipientListItem.class.getSimpleName();
@@ -84,10 +86,12 @@ public class MessageRecipientListItem extends RelativeLayout
final RecipientDeliveryStatus member,
final boolean isPushGroup)
{
if (this.member != null) this.member.getRecipient().live().removeForeverObserver(this);
this.glideRequests = glideRequests;
this.member = member;
member.getRecipient().addListener(this);
member.getRecipient().live().observeForever(this);
fromView.setText(member.getRecipient());
contactPhotoImage.setAvatar(glideRequests, member.getRecipient(), false);
setIssueIndicators(record, isPushGroup);
@@ -138,7 +142,7 @@ public class MessageRecipientListItem extends RelativeLayout
private NetworkFailure getNetworkFailure(final MessageRecord record) {
if (record.hasNetworkFailures()) {
for (final NetworkFailure failure : record.getNetworkFailures()) {
if (failure.getAddress().equals(member.getRecipient().getAddress())) {
if (failure.getRecipientId(getContext()).equals(member.getRecipient().getId())) {
return failure;
}
}
@@ -149,7 +153,7 @@ public class MessageRecipientListItem extends RelativeLayout
private IdentityKeyMismatch getKeyMismatch(final MessageRecord record) {
if (record.isIdentityMismatchFailure()) {
for (final IdentityKeyMismatch mismatch : record.getIdentityKeyMismatches()) {
if (mismatch.getAddress().equals(member.getRecipient().getAddress())) {
if (mismatch.getRecipientId(getContext()).equals(member.getRecipient().getId())) {
return mismatch;
}
}
@@ -158,14 +162,17 @@ public class MessageRecipientListItem extends RelativeLayout
}
public void unbind() {
if (this.member != null && this.member.getRecipient() != null) this.member.getRecipient().removeListener(this);
if (this.member != null && this.member.getRecipient() != null) this.member.getRecipient().live().removeForeverObserver(this);
}
@Override
public void onModified(final Recipient recipient) {
Util.runOnMain(() -> {
public void onRecipientChanged(@NonNull Recipient recipient) {
if (this.member != null && this.member.getRecipient().equals(recipient)) {
Log.d(TAG, "onRecipientChanged -- valid");
fromView.setText(recipient);
contactPhotoImage.setAvatar(glideRequests, recipient, false);
});
} else {
Log.d(TAG, "onRecipientChanged -- invalid");
}
}
}

View File

@@ -22,12 +22,29 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import org.thoughtcrime.securesms.conversation.ConversationActivity;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.libsignal.util.guava.Optional;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.UsernameUtil;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.io.IOException;
import java.util.UUID;
/**
* Activity container for starting a new conversation.
@@ -35,7 +52,9 @@ import org.thoughtcrime.securesms.recipients.Recipient;
* @author Moxie Marlinspike
*
*/
public class NewConversationActivity extends ContactSelectionActivity {
public class NewConversationActivity extends ContactSelectionActivity
implements ContactSelectionListFragment.InviteCallback
{
@SuppressWarnings("unused")
private static final String TAG = NewConversationActivity.class.getSimpleName();
@@ -48,11 +67,20 @@ public class NewConversationActivity extends ContactSelectionActivity {
}
@Override
public void onContactSelected(String number) {
Recipient recipient = Recipient.from(this, Address.fromExternal(this, number), true);
public void onContactSelected(Optional<RecipientId> recipientId, String number) {
Recipient recipient;
if (recipientId.isPresent()) {
recipient = Recipient.resolved(recipientId.get());
} else {
Log.i(TAG, "[onContactSelected] Maybe creating a new recipient.");
recipient = Recipient.external(this, number);
}
launch(recipient);
}
private void launch(Recipient recipient) {
Intent intent = new Intent(this, ConversationActivity.class);
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
intent.putExtra(ConversationActivity.RECIPIENT_EXTRA, recipient.getId());
intent.putExtra(ConversationActivity.TEXT_EXTRA, getIntent().getStringExtra(ConversationActivity.TEXT_EXTRA));
intent.setDataAndType(getIntent().getData(), getIntent().getType());
@@ -99,4 +127,9 @@ public class NewConversationActivity extends ContactSelectionActivity {
super.onPrepareOptionsMenu(menu);
return true;
}
@Override
public void onInvite() {
handleInvite();
}
}

View File

@@ -277,7 +277,7 @@ public class PassphrasePromptActivity extends PassphraseActivity {
fingerprintManager.authenticate(null, 0, fingerprintCancellationSignal, fingerprintListener, null);
} else if (Build.VERSION.SDK_INT >= 21){
Log.i(TAG, "firing intent...");
Intent intent = keyguardManager.createConfirmDeviceCredentialIntent("Unlock Signal", "");
Intent intent = keyguardManager.createConfirmDeviceCredentialIntent(getString(R.string.PassphrasePromptActivity_unlock_signal), "");
startActivityForResult(intent, 1);
} else {
Log.w(TAG, "Not compatible...");

View File

@@ -5,16 +5,20 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.migrations.ApplicationMigrationActivity;
import org.thoughtcrime.securesms.migrations.ApplicationMigrations;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.registration.WelcomeActivity;
import org.thoughtcrime.securesms.registration.RegistrationNavigationActivity;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
@@ -25,20 +29,19 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
public static final String LOCALE_EXTRA = "locale_extra";
private static final int STATE_NORMAL = 0;
private static final int STATE_CREATE_PASSPHRASE = 1;
private static final int STATE_PROMPT_PASSPHRASE = 2;
private static final int STATE_UPGRADE_DATABASE = 3;
private static final int STATE_PROMPT_PUSH_REGISTRATION = 4;
private static final int STATE_EXPERIENCE_UPGRADE = 5;
private static final int STATE_WELCOME_SCREEN = 6;
private static final int STATE_NORMAL = 0;
private static final int STATE_CREATE_PASSPHRASE = 1;
private static final int STATE_PROMPT_PASSPHRASE = 2;
private static final int STATE_UI_BLOCKING_UPGRADE = 3;
private static final int STATE_EXPERIENCE_UPGRADE = 4;
private static final int STATE_WELCOME_PUSH_SCREEN = 5;
private SignalServiceNetworkAccess networkAccess;
private BroadcastReceiver clearKeyReceiver;
@Override
protected final void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "onCreate(" + savedInstanceState + ")");
Log.d(TAG, "[" + Log.tag(getClass()) + "] onCreate()");
this.networkAccess = new SignalServiceNetworkAccess(this);
onPreCreate();
@@ -58,30 +61,42 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
@Override
protected void onResume() {
Log.i(TAG, "onResume()");
Log.d(TAG, "[" + Log.tag(getClass()) + "] onResume()");
super.onResume();
if (networkAccess.isCensored(this)) {
ApplicationContext.getInstance(this).getJobManager().add(new PushNotificationReceiveJob(this));
ApplicationDependencies.getJobManager().add(new PushNotificationReceiveJob(this));
}
}
@Override
protected void onStart() {
Log.d(TAG, "[" + Log.tag(getClass()) + "] onStart()");
super.onStart();
}
@Override
protected void onPause() {
Log.i(TAG, "onPause()");
Log.d(TAG, "[" + Log.tag(getClass()) + "] onPause()");
super.onPause();
}
@Override
protected void onStop() {
Log.d(TAG, "[" + Log.tag(getClass()) + "] onStop()");
super.onStop();
}
@Override
protected void onDestroy() {
Log.i(TAG, "onDestroy()");
Log.d(TAG, "[" + Log.tag(getClass()) + "] onDestroy()");
super.onDestroy();
removeClearKeyReceiver(this);
}
@Override
public void onMasterSecretCleared() {
Log.i(TAG, "onMasterSecretCleared()");
Log.d(TAG, "onMasterSecretCleared()");
if (ApplicationContext.getInstance(this).isAppVisible()) routeApplicationState(true);
else finish();
}
@@ -127,16 +142,15 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
}
private Intent getIntentForState(int state) {
Log.i(TAG, "routeApplicationState(), state: " + state);
Log.d(TAG, "routeApplicationState(), state: " + state);
switch (state) {
case STATE_CREATE_PASSPHRASE: return getCreatePassphraseIntent();
case STATE_PROMPT_PASSPHRASE: return getPromptPassphraseIntent();
case STATE_UPGRADE_DATABASE: return getUpgradeDatabaseIntent();
case STATE_WELCOME_SCREEN: return getWelcomeIntent();
case STATE_PROMPT_PUSH_REGISTRATION: return getPushRegistrationIntent();
case STATE_EXPERIENCE_UPGRADE: return getExperienceUpgradeIntent();
default: return null;
case STATE_CREATE_PASSPHRASE: return getCreatePassphraseIntent();
case STATE_PROMPT_PASSPHRASE: return getPromptPassphraseIntent();
case STATE_UI_BLOCKING_UPGRADE: return getUiBlockingUpgradeIntent();
case STATE_WELCOME_PUSH_SCREEN: return getPushRegistrationIntent();
case STATE_EXPERIENCE_UPGRADE: return getExperienceUpgradeIntent();
default: return null;
}
}
@@ -145,12 +159,10 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
return STATE_CREATE_PASSPHRASE;
} else if (locked) {
return STATE_PROMPT_PASSPHRASE;
} else if (DatabaseUpgradeActivity.isUpdate(this)) {
return STATE_UPGRADE_DATABASE;
} else if (!TextSecurePreferences.hasSeenWelcomeScreen(this)) {
return STATE_WELCOME_SCREEN;
} else if (ApplicationMigrations.isUpdate(this) && ApplicationMigrations.isUiBlockingMigrationRunning()) {
return STATE_UI_BLOCKING_UPGRADE;
} else if (!TextSecurePreferences.hasPromptedPushRegistration(this)) {
return STATE_PROMPT_PUSH_REGISTRATION;
return STATE_WELCOME_PUSH_SCREEN;
} else if (ExperienceUpgradeActivity.isUpdate(this)) {
return STATE_EXPERIENCE_UPGRADE;
} else {
@@ -166,8 +178,8 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
return getRoutedIntent(PassphrasePromptActivity.class, getIntent());
}
private Intent getUpgradeDatabaseIntent() {
return getRoutedIntent(DatabaseUpgradeActivity.class,
private Intent getUiBlockingUpgradeIntent() {
return getRoutedIntent(ApplicationMigrationActivity.class,
TextSecurePreferences.hasPromptedPushRegistration(this)
? getConversationListIntent()
: getPushRegistrationIntent());
@@ -177,16 +189,8 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
return getRoutedIntent(ExperienceUpgradeActivity.class, getIntent());
}
private Intent getWelcomeIntent() {
return getRoutedIntent(WelcomeActivity.class, getPushRegistrationIntent());
}
private Intent getPushRegistrationIntent() {
return getRoutedIntent(RegistrationActivity.class, getCreateProfileIntent());
}
private Intent getCreateProfileIntent() {
return getRoutedIntent(CreateProfileActivity.class, getConversationListIntent());
return RegistrationNavigationActivity.newIntentForNewRegistration(this);
}
private Intent getRoutedIntent(Class<?> destination, @Nullable Intent nextIntent) {
@@ -196,11 +200,11 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
}
private Intent getConversationListIntent() {
return new Intent(this, ConversationListActivity.class);
// TODO [greyson] Navigation
return new Intent(this, MainActivity.class);
}
private void initializeClearKeyReceiver() {
Log.i(TAG, "initializeClearKeyReceiver()");
this.clearKeyReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {

View File

@@ -19,6 +19,11 @@ package org.thoughtcrime.securesms;
import android.content.Intent;
import android.os.Bundle;
import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.contacts.SelectedContact;
import org.thoughtcrime.securesms.recipients.RecipientId;
import java.util.ArrayList;
import java.util.List;
@@ -30,6 +35,8 @@ import java.util.List;
*/
public class PushContactSelectionActivity extends ContactSelectionActivity {
public static final String KEY_SELECTED_RECIPIENTS = "recipients";
@SuppressWarnings("unused")
private final static String TAG = PushContactSelectionActivity.class.getSimpleName();
@@ -38,14 +45,13 @@ public class PushContactSelectionActivity extends ContactSelectionActivity {
getIntent().putExtra(ContactSelectionListFragment.MULTI_SELECT, true);
super.onCreate(icicle, ready);
getToolbar().setNavigationIcon(R.drawable.ic_check_white_24dp);
getToolbar().setNavigationIcon(R.drawable.ic_check_24);
getToolbar().setNavigationOnClickListener(v -> {
Intent resultIntent = getIntent();
List<String> selectedContacts = contactsFragment.getSelectedContacts();
Intent resultIntent = getIntent();
List<SelectedContact> selectedContacts = contactsFragment.getSelectedContacts();
List<RecipientId> recipients = Stream.of(selectedContacts).map(sc -> sc.getOrCreateRecipientId(this)).toList();
if (selectedContacts != null) {
resultIntent.putStringArrayListExtra("contacts", new ArrayList<>(selectedContacts));
}
resultIntent.putParcelableArrayListExtra(KEY_SELECTED_RECIPIENTS, new ArrayList<>(recipients));
setResult(RESULT_OK, resultIntent);
finish();

View File

@@ -9,6 +9,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil;
@@ -37,12 +38,11 @@ public class ReadReceiptsIntroFragment extends Fragment {
preference.setChecked(TextSecurePreferences.isReadReceiptsEnabled(getContext()));
preference.setOnCheckedChangeListener((buttonView, isChecked) -> {
TextSecurePreferences.setReadReceiptsEnabled(getContext(), isChecked);
ApplicationContext.getInstance(getContext())
.getJobManager()
.add(new MultiDeviceConfigurationUpdateJob(isChecked,
TextSecurePreferences.isTypingIndicatorsEnabled(requireContext()),
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(getContext()),
TextSecurePreferences.isLinkPreviewsEnabled(getContext())));
ApplicationDependencies.getJobManager()
.add(new MultiDeviceConfigurationUpdateJob(isChecked,
TextSecurePreferences.isTypingIndicatorsEnabled(requireContext()),
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(getContext()),
TextSecurePreferences.isLinkPreviewsEnabled(getContext())));
});
return v;

View File

@@ -13,84 +13,87 @@ import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.telephony.PhoneNumberUtils;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.Fragment;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader;
import androidx.core.view.ViewCompat;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.CheckBoxPreference;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.appcompat.widget.Toolbar;
import android.telephony.PhoneNumberUtils;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.color.MaterialColors;
import org.thoughtcrime.securesms.components.SwitchPreferenceCompat;
import org.thoughtcrime.securesms.components.ThreadPhotoRailView;
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.database.GroupDatabase;
import org.thoughtcrime.securesms.jobs.RotateProfileKeyJob;
import org.thoughtcrime.securesms.logging.Log;
import android.util.Pair;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.color.MaterialColors;
import org.thoughtcrime.securesms.components.ThreadPhotoRailView;
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.IdentityDatabase;
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
import org.thoughtcrime.securesms.database.MediaDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState;
import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader;
import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
import org.thoughtcrime.securesms.database.loaders.RecipientMediaLoader;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mediaoverview.MediaOverviewActivity;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.preferences.CorrectedPreferenceFragment;
import org.thoughtcrime.securesms.preferences.widgets.ColorPickerPreference;
import org.thoughtcrime.securesms.preferences.widgets.ContactPreference;
import org.thoughtcrime.securesms.recipients.LiveRecipient;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.Dialogs;
import org.thoughtcrime.securesms.util.DynamicDarkToolbarTheme;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.IdentityUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ThemeUtil;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.whispersystems.libsignal.util.guava.Optional;
import java.util.concurrent.ExecutionException;
@SuppressLint("StaticFieldLeak")
public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActivity implements RecipientModifiedListener, LoaderManager.LoaderCallbacks<Cursor>
public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActivity implements LoaderManager.LoaderCallbacks<Cursor>
{
private static final String TAG = RecipientPreferenceActivity.class.getSimpleName();
public static final String ADDRESS_EXTRA = "recipient_address";
public static final String RECIPIENT_ID = "recipient_address";
public static final String CAN_HAVE_SAFETY_NUMBER_EXTRA = "can_have_safety_number";
private static final String PREFERENCE_MUTED = "pref_key_recipient_mute";
@@ -104,12 +107,12 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
private static final String PREFERENCE_ABOUT = "pref_key_number";
private static final String PREFERENCE_CUSTOM_NOTIFICATIONS = "pref_key_recipient_custom_notifications";
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
private final DynamicTheme dynamicTheme = new DynamicDarkToolbarTheme();
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
private ImageView avatar;
private GlideRequests glideRequests;
private Address address;
private RecipientId recipientId;
private TextView threadPhotoRailLabel;
private ThreadPhotoRailView threadPhotoRailView;
private CollapsingToolbarLayout toolbarLayout;
@@ -124,13 +127,13 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
public void onCreate(Bundle instanceState, boolean ready) {
setContentView(R.layout.recipient_preference_activity);
this.glideRequests = GlideApp.with(this);
this.address = getIntent().getParcelableExtra(ADDRESS_EXTRA);
this.recipientId = getIntent().getParcelableExtra(RECIPIENT_ID);
Recipient recipient = Recipient.from(this, address, true);
LiveRecipient recipient = Recipient.live(recipientId);
initializeToolbar();
setHeader(recipient);
recipient.addListener(this);
setHeader(recipient.get());
recipient.observe(this, this::setHeader);
getSupportLoaderManager().initLoader(0, null, this);
}
@@ -173,13 +176,12 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
this.threadPhotoRailView = ViewUtil.findById(this, R.id.recent_photos);
this.threadPhotoRailLabel = ViewUtil.findById(this, R.id.rail_label);
this.toolbarLayout.setExpandedTitleColor(getResources().getColor(R.color.white));
this.toolbarLayout.setCollapsedTitleTextColor(getResources().getColor(R.color.white));
this.toolbarLayout.setExpandedTitleColor(ThemeUtil.getThemedColor(this, R.attr.conversation_title_color));
this.toolbarLayout.setCollapsedTitleTextColor(ThemeUtil.getThemedColor(this, R.attr.conversation_title_color));
this.threadPhotoRailView.setListener(mediaRecord -> {
Intent intent = new Intent(RecipientPreferenceActivity.this, MediaPreviewActivity.class);
intent.putExtra(MediaPreviewActivity.ADDRESS_EXTRA, address);
intent.putExtra(MediaPreviewActivity.OUTGOING_EXTRA, mediaRecord.isOutgoing());
intent.putExtra(MediaPreviewActivity.THREAD_ID_EXTRA, mediaRecord.getThreadId());
intent.putExtra(MediaPreviewActivity.DATE_EXTRA, mediaRecord.getDate());
intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, mediaRecord.getAttachment().getSize());
intent.putExtra(MediaPreviewActivity.CAPTION_EXTRA, mediaRecord.getAttachment().getCaption());
@@ -188,11 +190,16 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
startActivity(intent);
});
this.threadPhotoRailLabel.setOnClickListener(v -> {
Intent intent = new Intent(this, MediaOverviewActivity.class);
intent.putExtra(MediaOverviewActivity.ADDRESS_EXTRA, address);
startActivity(intent);
});
SimpleTask.run(
() -> DatabaseFactory.getThreadDatabase(this).getThreadIdFor(recipientId),
(threadId) -> {
if (threadId == null) {
Log.i(TAG, "No thread id for recipient.");
} else {
this.threadPhotoRailLabel.setOnClickListener(v -> startActivity(MediaOverviewActivity.forThread(this, threadId)));
}
}
);
Toolbar toolbar = ViewUtil.findById(this, R.id.toolbar);
setSupportActionBar(toolbar);
@@ -202,13 +209,18 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().setStatusBarColor(Color.TRANSPARENT);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.recipient_preference_root), (v, insets) -> {
ViewUtil.setTopMargin(toolbar, insets.getSystemWindowInsetTop());
return insets;
});
}
}
private void setHeader(@NonNull Recipient recipient) {
ContactPhoto contactPhoto = recipient.isLocalNumber() ? new ProfileContactPhoto(recipient.getAddress(), String.valueOf(TextSecurePreferences.getProfileAvatarId(this)))
ContactPhoto contactPhoto = recipient.isLocalNumber() ? new ProfileContactPhoto(recipient.getId(), String.valueOf(TextSecurePreferences.getProfileAvatarId(this)))
: recipient.getContactPhoto();
FallbackContactPhoto fallbackPhoto = recipient.isLocalNumber() ? new ResourceContactPhoto(R.drawable.ic_profile_default, R.drawable.ic_person_large)
FallbackContactPhoto fallbackPhoto = recipient.isLocalNumber() ? new ResourceContactPhoto(R.drawable.ic_profile_outline_40, R.drawable.ic_profile_outline_20, R.drawable.ic_person_large)
: recipient.getFallbackContactPhoto();
glideRequests.load(contactPhoto)
@@ -221,18 +233,13 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
else this.avatar.setScaleType(ImageView.ScaleType.CENTER_CROP);
this.avatar.setBackgroundColor(recipient.getColor().toActionBarColor(this));
this.toolbarLayout.setTitle(recipient.toShortString());
this.toolbarLayout.setTitle(recipient.toShortString(this));
this.toolbarLayout.setContentScrimColor(recipient.getColor().toActionBarColor(this));
}
@Override
public void onModified(final Recipient recipient) {
Util.runOnMain(() -> setHeader(recipient));
}
@Override
public @NonNull Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new ThreadMediaLoader(this, address, true);
return new RecipientMediaLoader(this, recipientId, RecipientMediaLoader.MediaType.GALLERY, MediaDatabase.Sorting.Newest);
}
@Override
@@ -248,7 +255,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
this.threadPhotoRailView.setCursor(glideRequests, data);
Bundle bundle = new Bundle();
bundle.putParcelable(ADDRESS_EXTRA, address);
bundle.putParcelable(RECIPIENT_ID, recipientId);
initFragment(R.id.preference_fragment, new RecipientPreferenceFragment(), null, bundle);
}
@@ -257,12 +264,9 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
this.threadPhotoRailView.setCursor(glideRequests, null);
}
public static class RecipientPreferenceFragment
extends CorrectedPreferenceFragment
implements RecipientModifiedListener
{
private Recipient recipient;
private boolean canHaveSafetyNumber;
public static class RecipientPreferenceFragment extends CorrectedPreferenceFragment {
private LiveRecipient recipient;
private boolean canHaveSafetyNumber;
@Override
public void onCreate(Bundle icicle) {
@@ -277,20 +281,20 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
Preference customNotificationsPref = this.findPreference(PREFERENCE_CUSTOM_NOTIFICATIONS);
if (NotificationChannels.supported()) {
((SwitchPreferenceCompat) customNotificationsPref).setChecked(recipient.getNotificationChannel() != null);
((SwitchPreferenceCompat) customNotificationsPref).setChecked(recipient.get().getNotificationChannel() != null);
customNotificationsPref.setOnPreferenceChangeListener(new CustomNotificationsChangedListener());
this.findPreference(PREFERENCE_MESSAGE_TONE).setDependency(PREFERENCE_CUSTOM_NOTIFICATIONS);
this.findPreference(PREFERENCE_MESSAGE_VIBRATE).setDependency(PREFERENCE_CUSTOM_NOTIFICATIONS);
if (recipient.getNotificationChannel() != null) {
final Context context = getContext();
if (recipient.get().getNotificationChannel() != null) {
final Context context = requireContext();
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
RecipientDatabase db = DatabaseFactory.getRecipientDatabase(getContext());
db.setMessageRingtone(recipient, NotificationChannels.getMessageRingtone(context, recipient));
db.setMessageVibrate(recipient, NotificationChannels.getMessageVibrate(context, recipient) ? VibrateState.ENABLED : VibrateState.DISABLED);
db.setMessageRingtone(recipient.getId(), NotificationChannels.getMessageRingtone(context, recipient.get()));
db.setMessageVibrate(recipient.getId(), NotificationChannels.getMessageVibrate(context, recipient.get()) ? VibrateState.ENABLED : VibrateState.DISABLED);
NotificationChannels.ensureCustomChannelConsistency(context);
return null;
}
@@ -336,13 +340,12 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
@Override
public void onResume() {
super.onResume();
setSummaries(recipient);
setSummaries(recipient.get());
}
@Override
public void onDestroy() {
super.onDestroy();
this.recipient.removeListener(this);
}
@Override
@@ -358,9 +361,17 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
}
}
@Override
public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
RecyclerView recyclerView = super.onCreateRecyclerView(inflater, parent, savedInstanceState);
recyclerView.setItemAnimator(null);
recyclerView.setLayoutAnimation(null);
return recyclerView;
}
private void initializeRecipients() {
this.recipient = Recipient.from(getActivity(), getArguments().getParcelable(ADDRESS_EXTRA), true);
this.recipient.addListener(this);
this.recipient = Recipient.live(getArguments().getParcelable(RECIPIENT_ID));
this.recipient.observe(this, this::setSummaries);
}
private void setSummaries(Recipient recipient) {
@@ -394,6 +405,10 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
vibrateCallPreference.setSummary(vibrateCallSummary.first);
vibrateCallPreference.setValueIndex(vibrateCallSummary.second);
blockPreference.setVisible(RecipientUtil.isBlockable(recipient));
if (recipient.isBlocked()) blockPreference.setTitle(R.string.RecipientPreferenceActivity_unblock);
else blockPreference.setTitle(R.string.RecipientPreferenceActivity_block);
if (recipient.isLocalNumber()) {
mutePreference.setVisible(false);
customPreference.setVisible(false);
@@ -406,7 +421,9 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
if (privacyCategory != null) privacyCategory.setVisible(false);
if (divider != null) divider.setVisible(false);
if (callCategory != null) callCategory.setVisible(false);
} if (recipient.isGroupRecipient()) {
}
if (recipient.isGroup()) {
if (colorPreference != null) colorPreference.setVisible(false);
if (identityPreference != null) identityPreference.setVisible(false);
if (callCategory != null) callCategory.setVisible(false);
@@ -414,16 +431,19 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
if (aboutDivider != null) aboutDivider.setVisible(false);
if (divider != null) divider.setVisible(false);
} else {
colorPreference.setColors(MaterialColors.CONVERSATION_PALETTE.asConversationColorArray(getActivity()));
colorPreference.setColor(recipient.getColor().toActionBarColor(getActivity()));
colorPreference.setColors(MaterialColors.CONVERSATION_PALETTE.asConversationColorArray(requireActivity()));
colorPreference.setColor(recipient.getColor().toActionBarColor(requireActivity()));
if (FeatureFlags.PROFILE_DISPLAY) {
aboutPreference.setTitle(recipient.getDisplayName(requireContext()));
aboutPreference.setSummary(recipient.resolve().getE164().or(""));
} else {
aboutPreference.setTitle(formatRecipient(recipient));
aboutPreference.setSummary(recipient.getCustomLabel());
}
aboutPreference.setTitle(formatAddress(recipient.getAddress()));
aboutPreference.setSummary(recipient.getCustomLabel());
aboutPreference.setSecure(recipient.getRegistered() == RecipientDatabase.RegisteredState.REGISTERED);
if (recipient.isBlocked()) blockPreference.setTitle(R.string.RecipientPreferenceActivity_unblock);
else blockPreference.setTitle(R.string.RecipientPreferenceActivity_block);
IdentityUtil.getRemoteIdentityKey(getActivity(), recipient).addListener(new ListenableFuture.Listener<Optional<IdentityRecord>>() {
@Override
public void onSuccess(Optional<IdentityRecord> result) {
@@ -444,12 +464,16 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
}
});
}
if (recipient.isMmsGroup() && privacyCategory != null) {
privacyCategory.setVisible(false);
}
}
private @NonNull String formatAddress(@NonNull Address address) {
if (address.isPhone()) return PhoneNumberUtils.formatNumber(address.toPhoneString());
else if (address.isEmail()) return address.toEmailString();
else return "";
private @NonNull String formatRecipient(@NonNull Recipient recipient) {
if (recipient.getE164().isPresent()) return PhoneNumberUtils.formatNumber(recipient.requireE164());
else if (recipient.getEmail().isPresent()) return recipient.requireEmail();
else return "";
}
private @NonNull String getRingtoneSummary(@NonNull Context context, @Nullable Uri ringtone) {
@@ -478,15 +502,6 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
}
}
@Override
public void onModified(final Recipient recipient) {
Util.runOnMain(() -> {
if (getContext() != null && getActivity() != null && !getActivity().isFinishing()) {
setSummaries(recipient);
}
});
}
private class RingtoneChangeListener implements Preference.OnPreferenceChangeListener {
private final boolean calls;
@@ -514,10 +529,10 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
@Override
protected Void doInBackground(Uri... params) {
if (calls) {
DatabaseFactory.getRecipientDatabase(context).setCallRingtone(recipient, params[0]);
DatabaseFactory.getRecipientDatabase(context).setCallRingtone(recipient.getId(), params[0]);
} else {
DatabaseFactory.getRecipientDatabase(context).setMessageRingtone(recipient, params[0]);
NotificationChannels.updateMessageRingtone(context, recipient, params[0]);
DatabaseFactory.getRecipientDatabase(context).setMessageRingtone(recipient.getId(), params[0]);
NotificationChannels.updateMessageRingtone(context, recipient.get(), params[0]);
}
return null;
}
@@ -541,10 +556,10 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
Uri defaultUri;
if (calls) {
current = recipient.getCallRingtone();
current = recipient.get().getCallRingtone();
defaultUri = TextSecurePreferences.getCallNotificationRingtone(getContext());
} else {
current = recipient.getMessageRingtone();
current = recipient.get().getMessageRingtone();
defaultUri = TextSecurePreferences.getNotificationRingtone(getContext());
}
@@ -582,11 +597,11 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
@Override
protected Void doInBackground(Void... params) {
if (call) {
DatabaseFactory.getRecipientDatabase(context).setCallVibrate(recipient, vibrateState);
DatabaseFactory.getRecipientDatabase(context).setCallVibrate(recipient.getId(), vibrateState);
}
else {
DatabaseFactory.getRecipientDatabase(context).setMessageVibrate(recipient, vibrateState);
NotificationChannels.updateMessageVibrate(context, recipient, vibrateState);
DatabaseFactory.getRecipientDatabase(context).setMessageVibrate(recipient.getId(), vibrateState);
NotificationChannels.updateMessageVibrate(context, recipient.get(), vibrateState);
}
return null;
}
@@ -605,7 +620,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
final int value = (Integer) newValue;
final MaterialColor selectedColor = MaterialColors.CONVERSATION_PALETTE.getByColor(context, value);
final MaterialColor currentColor = recipient.getColor();
final MaterialColor currentColor = recipient.get().getColor();
if (selectedColor == null) return true;
@@ -613,12 +628,10 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
DatabaseFactory.getRecipientDatabase(context).setColor(recipient, selectedColor);
DatabaseFactory.getRecipientDatabase(context).setColor(recipient.getId(), selectedColor);
if (recipient.resolve().getRegistered() == RecipientDatabase.RegisteredState.REGISTERED) {
ApplicationContext.getInstance(context)
.getJobManager()
.add(new MultiDeviceContactUpdateJob(context, recipient.getAddress()));
if (recipient.get().resolve().getRegistered() == RecipientDatabase.RegisteredState.REGISTERED) {
ApplicationDependencies.getJobManager().add(new MultiDeviceContactUpdateJob(recipient.getId()));
}
return null;
}
@@ -632,30 +645,28 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
@Override
public boolean onPreferenceClick(Preference preference) {
if (recipient.isMuted()) handleUnmute(preference.getContext());
else handleMute(preference.getContext());
if (recipient.get().isMuted()) handleUnmute(preference.getContext());
else handleMute(preference.getContext());
return true;
}
private void handleMute(@NonNull Context context) {
MuteDialog.show(context, until -> setMuted(context, recipient, until));
MuteDialog.show(context, until -> setMuted(context, recipient.get(), until));
setSummaries(recipient);
setSummaries(recipient.get());
}
private void handleUnmute(@NonNull Context context) {
setMuted(context, recipient, 0);
setMuted(context, recipient.get(), 0);
}
private void setMuted(@NonNull final Context context, final Recipient recipient, final long until) {
recipient.setMuted(until);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
DatabaseFactory.getRecipientDatabase(context)
.setMuted(recipient, until);
.setMuted(recipient.getId(), until);
return null;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@@ -674,7 +685,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
@Override
public boolean onPreferenceClick(Preference preference) {
Intent verifyIdentityIntent = new Intent(preference.getContext(), VerifyIdentityActivity.class);
verifyIdentityIntent.putExtra(VerifyIdentityActivity.ADDRESS_EXTRA, recipient.getAddress());
verifyIdentityIntent.putExtra(VerifyIdentityActivity.RECIPIENT_EXTRA, recipient.getId());
verifyIdentityIntent.putExtra(VerifyIdentityActivity.IDENTITY_EXTRA, new IdentityKeyParcelable(identityKey.getIdentityKey()));
verifyIdentityIntent.putExtra(VerifyIdentityActivity.VERIFIED_EXTRA, identityKey.getVerifiedStatus() == IdentityDatabase.VerifiedStatus.VERIFIED);
startActivity(verifyIdentityIntent);
@@ -686,8 +697,8 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
private class BlockClickedListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
if (recipient.isBlocked()) handleUnblock(preference.getContext());
else handleBlock(preference.getContext());
if (recipient.get().isBlocked()) handleUnblock(preference.getContext());
else handleBlock(preference.getContext());
return true;
}
@@ -700,10 +711,10 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
int titleRes = R.string.RecipientPreferenceActivity_block_this_contact_question;
int bodyRes = R.string.RecipientPreferenceActivity_you_will_no_longer_receive_messages_and_calls_from_this_contact;
if (recipient.isGroupRecipient()) {
if (recipient.get().isGroup()) {
bodyRes = R.string.RecipientPreferenceActivity_block_and_leave_group_description;
if (recipient.isGroupRecipient() && DatabaseFactory.getGroupDatabase(context).isActive(recipient.getAddress().toGroupString())) {
if (recipient.get().isGroup() && DatabaseFactory.getGroupDatabase(context).isActive(recipient.get().requireGroupId())) {
titleRes = R.string.RecipientPreferenceActivity_block_and_leave_group;
} else {
titleRes = R.string.RecipientPreferenceActivity_block_group;
@@ -721,7 +732,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
.setCancelable(true)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(R.string.RecipientPreferenceActivity_block, (dialog, which) -> {
setBlocked(context, recipient, true);
setBlocked(context, recipient.get(), true);
}).show();
}
}.execute();
@@ -731,7 +742,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
int titleRes = R.string.RecipientPreferenceActivity_unblock_this_contact_question;
int bodyRes = R.string.RecipientPreferenceActivity_you_will_once_again_be_able_to_receive_messages_and_calls_from_this_contact;
if (recipient.isGroupRecipient()) {
if (recipient.resolve().isGroup()) {
titleRes = R.string.RecipientPreferenceActivity_unblock_this_group_question;
bodyRes = R.string.RecipientPreferenceActivity_unblock_this_group_description;
}
@@ -741,45 +752,17 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
.setMessage(bodyRes)
.setCancelable(true)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(R.string.RecipientPreferenceActivity_unblock, (dialog, which) -> setBlocked(context, recipient, false)).show();
.setPositiveButton(R.string.RecipientPreferenceActivity_unblock, (dialog, which) -> setBlocked(context, recipient.get(), false)).show();
}
private void setBlocked(@NonNull final Context context, final Recipient recipient, final boolean blocked) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
DatabaseFactory.getRecipientDatabase(context)
.setBlocked(recipient, blocked);
if (recipient.isGroupRecipient() && DatabaseFactory.getGroupDatabase(context).isActive(recipient.getAddress().toGroupString())) {
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient);
Optional<OutgoingGroupMediaMessage> leaveMessage = GroupUtil.createGroupLeaveMessage(context, recipient);
if (threadId != -1 && leaveMessage.isPresent()) {
MessageSender.send(context, leaveMessage.get(), threadId, false, null);
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
String groupId = recipient.getAddress().toGroupString();
groupDatabase.setActive(groupId, false);
groupDatabase.remove(groupId, Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)));
} else {
Log.w(TAG, "Failed to leave group. Can't block.");
Toast.makeText(context, R.string.RecipientPreferenceActivity_error_leaving_group, Toast.LENGTH_LONG).show();
}
}
if (blocked && (recipient.resolve().isSystemContact() || recipient.resolve().isProfileSharing())) {
ApplicationContext.getInstance(context)
.getJobManager()
.add(new RotateProfileKeyJob());
}
ApplicationContext.getInstance(context)
.getJobManager()
.add(new MultiDeviceBlockedUpdateJob());
return null;
SignalExecutors.BOUNDED.execute(() -> {
if (blocked) {
RecipientUtil.block(context, recipient);
} else {
RecipientUtil.unblock(context, recipient);
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
});
}
}
@@ -787,19 +770,24 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
@Override
public void onMessageClicked() {
CommunicationActions.startConversation(getContext(), recipient, null);
CommunicationActions.startConversation(getContext(), recipient.get(), null);
}
@Override
public void onSecureCallClicked() {
CommunicationActions.startVoiceCall(getActivity(), recipient);
CommunicationActions.startVoiceCall(getActivity(), recipient.get());
}
@Override
public void onSecureVideoClicked() {
CommunicationActions.startVideoCall(getActivity(), recipient.get());
}
@Override
public void onInSecureCallClicked() {
try {
Intent dialIntent = new Intent(Intent.ACTION_DIAL,
Uri.parse("tel:" + recipient.getAddress().serialize()));
Uri.parse("tel:" + recipient.get().requireE164()));
startActivity(dialIntent);
} catch (ActivityNotFoundException anfe) {
Log.w(TAG, anfe);
@@ -821,11 +809,11 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
@Override
protected Void doInBackground(Void... params) {
if (enabled) {
String channel = NotificationChannels.createChannelFor(context, recipient);
DatabaseFactory.getRecipientDatabase(context).setNotificationChannel(recipient, channel);
String channel = NotificationChannels.createChannelFor(context, recipient.get());
DatabaseFactory.getRecipientDatabase(context).setNotificationChannel(recipient.getId(), channel);
} else {
NotificationChannels.deleteChannelFor(context, recipient);
DatabaseFactory.getRecipientDatabase(context).setNotificationChannel(recipient, null);
NotificationChannels.deleteChannelFor(context, recipient.get());
DatabaseFactory.getRecipientDatabase(context).setNotificationChannel(recipient.getId(), null);
}
return null;
}

View File

@@ -24,7 +24,6 @@ import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Process;
import android.provider.OpenableColumns;
import androidx.annotation.NonNull;
@@ -39,7 +38,6 @@ import android.widget.ImageView;
import org.thoughtcrime.securesms.components.SearchToolbar;
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
import org.thoughtcrime.securesms.conversation.ConversationActivity;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.logging.Log;
@@ -47,6 +45,7 @@ import org.thoughtcrime.securesms.mediasend.Media;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.stickers.StickerLocator;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
@@ -55,6 +54,9 @@ import org.thoughtcrime.securesms.util.FileUtils;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.whispersystems.libsignal.util.Pair;
import org.whispersystems.libsignal.util.guava.Optional;
import java.io.FileInputStream;
import java.io.IOException;
@@ -72,7 +74,7 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
private static final String TAG = ShareActivity.class.getSimpleName();
public static final String EXTRA_THREAD_ID = "thread_id";
public static final String EXTRA_ADDRESS_MARSHALLED = "address_marshalled";
public static final String EXTRA_RECIPIENT_ID = "recipient_id";
public static final String EXTRA_DISTRIBUTION_TYPE = "distribution_type";
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
@@ -95,10 +97,13 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
@Override
protected void onCreate(Bundle icicle, boolean ready) {
if (!getIntent().hasExtra(ContactSelectionListFragment.DISPLAY_MODE)) {
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE,
TextSecurePreferences.isSmsEnabled(this)
? DisplayMode.FLAG_ALL
: DisplayMode.FLAG_PUSH | DisplayMode.FLAG_GROUPS);
int mode = DisplayMode.FLAG_PUSH | DisplayMode.FLAG_ACTIVE_GROUPS;
if (TextSecurePreferences.isSmsEnabled(this)) {
mode |= DisplayMode.FLAG_SMS;
}
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, mode);
}
getIntent().putExtra(ContactSelectionListFragment.REFRESHABLE, false);
@@ -216,35 +221,30 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
}
private void handleResolvedMedia(Intent intent, boolean animate) {
long threadId = intent.getLongExtra(EXTRA_THREAD_ID, -1);
int distributionType = intent.getIntExtra(EXTRA_DISTRIBUTION_TYPE, -1);
Address address = null;
long threadId = intent.getLongExtra(EXTRA_THREAD_ID, -1);
int distributionType = intent.getIntExtra(EXTRA_DISTRIBUTION_TYPE, -1);
RecipientId recipientId = null;
if (intent.hasExtra(EXTRA_ADDRESS_MARSHALLED)) {
Parcel parcel = Parcel.obtain();
byte[] marshalled = intent.getByteArrayExtra(EXTRA_ADDRESS_MARSHALLED);
parcel.unmarshall(marshalled, 0, marshalled.length);
parcel.setDataPosition(0);
address = parcel.readParcelable(getClassLoader());
parcel.recycle();
if (intent.hasExtra(EXTRA_RECIPIENT_ID)) {
recipientId = RecipientId.from(intent.getStringExtra(EXTRA_RECIPIENT_ID));
}
boolean hasResolvedDestination = threadId != -1 && address != null && distributionType != -1;
boolean hasResolvedDestination = threadId != -1 && recipientId != null && distributionType != -1;
if (!hasResolvedDestination && animate) {
ViewUtil.fadeIn(contactsFragment.getView(), 300);
if (hasResolvedDestination) {
createConversation(threadId, recipientId, distributionType);
} else if (animate) {
ViewUtil.fadeIn(contactsFragment.requireView(), 300);
ViewUtil.fadeOut(progressWheel, 300);
} else if (!hasResolvedDestination) {
contactsFragment.getView().setVisibility(View.VISIBLE);
progressWheel.setVisibility(View.GONE);
} else {
createConversation(threadId, address, distributionType);
contactsFragment.requireView().setVisibility(View.VISIBLE);
progressWheel.setVisibility(View.GONE);
}
}
private void createConversation(long threadId, Address address, int distributionType) {
private void createConversation(long threadId, @NonNull RecipientId recipientId, int distributionType) {
final Intent intent = getBaseShareIntent(ConversationActivity.class);
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, address);
intent.putExtra(ConversationActivity.RECIPIENT_EXTRA, recipientId);
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);
@@ -276,14 +276,25 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
}
@Override
public void onContactSelected(String number) {
Recipient recipient = Recipient.from(this, Address.fromExternal(this, number), true);
long existingThread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient);
createConversation(existingThread, recipient.getAddress(), ThreadDatabase.DistributionTypes.DEFAULT);
public void onContactSelected(Optional<RecipientId> recipientId, String number) {
SimpleTask.run(this.getLifecycle(), () -> {
Recipient recipient;
if (recipientId.isPresent()) {
recipient = Recipient.resolved(recipientId.get());
} else {
Log.i(TAG, "[onContactSelected] Maybe creating a new recipient.");
recipient = Recipient.external(this, number);
}
long existingThread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient);
return new Pair<>(existingThread, recipient);
}, result -> {
createConversation(result.first(), result.second().getId(), ThreadDatabase.DistributionTypes.DEFAULT);
});
}
@Override
public void onContactDeselected(String number) {
public void onContactDeselected(@NonNull Optional<RecipientId> recipientId, String number) {
}

View File

@@ -1,6 +1,5 @@
package org.thoughtcrime.securesms;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@@ -10,40 +9,40 @@ import androidx.core.app.TaskStackBuilder;
import androidx.appcompat.app.AppCompatActivity;
import android.widget.Toast;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.CommunicationActions;
public class ShortcutLauncherActivity extends AppCompatActivity {
private static final String KEY_SERIALIZED_ADDRESS = "serialized_address";
private static final String KEY_RECIPIENT = "recipient_id";
public static Intent createIntent(@NonNull Context context, @NonNull Address address) {
public static Intent createIntent(@NonNull Context context, @NonNull RecipientId recipientId) {
Intent intent = new Intent(context, ShortcutLauncherActivity.class);
intent.setAction(Intent.ACTION_MAIN);
intent.putExtra(KEY_SERIALIZED_ADDRESS, address.serialize());
intent.putExtra(KEY_RECIPIENT, recipientId.serialize());
return intent;
}
@SuppressLint("StaticFieldLeak")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String serializedAddress = getIntent().getStringExtra(KEY_SERIALIZED_ADDRESS);
String rawId = getIntent().getStringExtra(KEY_RECIPIENT);
if (serializedAddress == null) {
if (rawId == null) {
Toast.makeText(this, R.string.ShortcutLauncherActivity_invalid_shortcut, Toast.LENGTH_SHORT).show();
startActivity(new Intent(this, ConversationListActivity.class));
// TODO [greyson] Navigation
startActivity(new Intent(this, MainActivity.class));
finish();
return;
}
Address address = Address.fromSerialized(serializedAddress);
Recipient recipient = Recipient.from(this, address, true);
Recipient recipient = Recipient.live(RecipientId.from(rawId)).get();
// TODO [greyson] Navigation
TaskStackBuilder backStack = TaskStackBuilder.create(this)
.addNextIntent(new Intent(this, ConversationListActivity.class));
.addNextIntent(new Intent(this, MainActivity.class));
CommunicationActions.startConversation(this, recipient, null, backStack);
finish();

View File

@@ -12,7 +12,6 @@ import org.thoughtcrime.securesms.conversation.ConversationActivity;
import org.thoughtcrime.securesms.logging.Log;
import android.widget.Toast;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.Rfc5724Uri;
@@ -48,13 +47,13 @@ public class SmsSendtoActivity extends Activity {
nextIntent.putExtra(ConversationActivity.TEXT_EXTRA, destination.getBody());
Toast.makeText(this, R.string.ConversationActivity_specify_recipient, Toast.LENGTH_LONG).show();
} else {
Recipient recipient = Recipient.from(this, Address.fromExternal(this, destination.getDestination()), true);
Recipient recipient = Recipient.external(this, destination.getDestination());
long threadId = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient);
nextIntent = new Intent(this, ConversationActivity.class);
nextIntent.putExtra(ConversationActivity.TEXT_EXTRA, destination.getBody());
nextIntent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
nextIntent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress());
nextIntent.putExtra(ConversationActivity.RECIPIENT_EXTRA, recipient.getId());
}
return nextIntent;
}

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