There are several (popular) phone models out there that have bugs in
their MediaPlayer implementation that cause them to be unable to play
voice notes. By moving to ExoPlayer, an application-level media player,
we should avoid most of these headaches and stardardize playback.
Fixes#7748
In the case where we add new fields to a Job's InputData, we want to
make sure that initialize() is called in the try block so that if it
fails, it simply fails the job (allowing the user to retry with the new
field) instead of crashing.
This is to guard against behavior WorkManager has where it may
re-enqueue a job that has already been completed (if, for instance, it
was preempted).
Fixes#8268
The aim of this is to help performance by breaking up the single massive
spritesheet into smaller ones. This will limit the amount of data that
needs to be kept in memory to render emoji.
(Hopefully) Fixes#8357
Because SMS sending is split over two jobs, there's no max retry limit
respected if we find out about the failure in SmsSentJob -- it's
requeued as a new job with a fresh attempt counter.
This commit carries a retry count between the two jobs. It also verifies
that we have service before attempting to send a message at all.
Relates to #8268
There are rare corner cases where a Job could be preempted by the
JobScheduler and then be rescheduled before the preempted job finished
running. This could create weird race conditions with bad consequences.
To fix this, we create a fun locking system that prevents two jobs with
the same UUID from running at the same time.
Includes display support for more genders, and more notably, skin tones.
These are not currently selectable in the UI, but they will be rendered
properly when other clients send them.
There's some ANRs, not many, that are likely caused by us riding the
5-second ANR timeout a little too closely. Giving us a little buffer to
see if that helps.
Some phones, notably the Pixel 3, had some problems with scaling after
taking photos. This fixes it by using the takePicture API instead of
pulling the bitmap from the TextureView.
Fixes#8292
Android P's new ringtone selector is a whole new activity that can cause
RecipientPreferenceActivity to go through the full onCreate() flow after
the ringtone selection. This could cause a race between setting the
preference and reading the preference from the notification channel.
Just threw them on a serial executor to guarantee ordering.
Due to an Android P bug, we basically need to stop calling
startService() in onResume()/onPause(). That means I had to turn
MessageRetrieval service into a singlton instead of a service. I also
moved the offending KeyCachingService calls into static methods that
didn't have to start the service.
If we already have two active processing GCM messages, there's no
benefit to a third. In fact, enqueuing additional ones will likely only
end up showing the foreground notification unnecessariliy.
Previously we were starting a background service, which isn't allowed
for targetSdk 26. This will do the same thing but at a time decided by
the system.
This gives us more control over when it happens, as well as lets us set
things like the debug level. Also let's us get rid of the synchronized
block we had in Application#onCreate().
This sound isn't supposed to play when you have notification sound off,
but apparently some Huawei phones will play it anyway. Until we can
figure out a better way to handle it, we're just removing it.
We don't store non-user-selected colors in the database. That means that
when we update the palette, we still have to hash based off of the legacy
palette when generating a color if we want to migrate to a
similar-looking color.
Unfortunately, because the new palette is smaller, some colors are
"overloaded", meaning that when we hash based off of the legacy palette,
some colors will be more/less common than others. To fix this, we simply
persist all current colors in the database, then switch our hashing list
to what we really want.
Occasionally a job may be run when the app is in a network-restricted
mode, like a form of doze. When this happens, jobs can timeout due to
lack of network access, causing a cascade of job delays. This is
particularly bad in the case of message retrieval.
To prevent this, if a job that normally requires network detects that no
network is available when running, then we start a foreground
notification.
Some devices will randomly throw RuntimeExceptions here due to hardware
issues. We were already doing broader catch statement in CameraView, so
I moved it here as well.
Unfortunately, while there does exist an XML property to disable the
indentation, it's bugged for category headings, so we have to do this
silly thing where we strip the padding in the adapter. Hopefully they'll
fix the bug and we can move to use the sanctioned property.
See: https://issuetracker.google.com/issues/111662669Fixes#8233
On older versions of Android, TextureView#getBitmap() needs to be called
on the main thread. On mid range phones, this is ~50ms. Normally that'd
be bad, but the UI isn't doing anything at that point anyway.
Fixes#8232
We were being inconsistent in how we were handling exiting multiselect,
and it wasn't behaving properly when you left by clicking the 'x'. Now
it's all handled centrally.
Fixes#8234
A new, fullscreen camera capture flow that easily allows you to capture
and edit a photo before sending it. Replaces the current half-screen
camera button.
Keep the single-use behavior, but allow the creation of multi-use memory
blobs that can be deleted when we're done with them. Will help out with
having URI's for temporary images during the camera capture flow.
This also fixes the situation where we block group-leave messages,
preventing blocked contacts from leaving groups.
Fixes#7970
Also, this forced us to upgrade libsignal-service, which fixes the
websocket timeout issues. Thanks to @dpapavas!
Fixes#6644
Forwarding of shared contacts currently just creates an empty draft.
You can't preview a shared contact before you send, which would make the
forwarding flow inconsistent across media types. So it's easier to just
hide it for now.
Fixes#8195
This could cause us to think push messages were actually sent with
a SIM. We also now prevent rendering SIM info on push messages in
the conversation view.
Fixes#8176
We were hitting the transaction limit size. This change scales down
shortcut icons to be at most 300x300, which comes out to ~360kb, which
should be safely under the limit of 1mb.
Fixes#8139
We were getting an IllegalArgumentException during channel creation on
some Samsung phones. Stack trace didn't give me much more than that, so
just adding in some additional safeguards that make sense based on
reading AOSP.
We manually play the ringtone when in-thread notifications are enabled,
but we weren't using the sound specified by the channel in the system
settings. This fixes that problem by reading the NotificationChannel
setting.
We were getting a TransactionTooLargeException when giving an
EditText a very large (1.5MB+) text block. This has been resolved
by switching to a RecyclerView to show the text line-by-line. As a
side-effect, this improves scroll performance on lower-end devices.
Also, I added a button to jump to the bottom of the log because I
really wanted one :)
Fixes#8124
Previously, we were making a new copy of the entire source string after
every scrubbed substitution. In the case of our new, larger log files,
this was very slow. It's been changed so we only ever create one new
copy.
In practice, on a Moto E (2014), scrubbing a 1.5MB log went from
>4000ms to ~100ms.
When using notification channels, us setting priority actually has
no effect. So instead of having a non-functional setting, we've
routed the notification priority setting to go to the system
notification channel settings page for our Messages channel.
Address linkification on Android is pretty busted, and the docs
acknowledge it (see Linkify#MAP_ADDRESSES). Safest thing to do
at the moment is remove it. Looks like we may be able to get
better address linkification on API >= 28, but adding it will
be more involved.
Fixes#7730
Previously, we'd only show the attachment button when the user had
yet to enter any text. To add an attachment after text was entered,
you'd have to go to the three-dot menu. Now we just show a little
attach button in the text area.
I also took the opportunity to clean up other button paddings and
stuff in the compose area so things look better and react to text
sizes more predictably.
Added a new logger that persists logs for a longer duration to the
user's cache directory. Logs are encrypted. The new logs are sent
in addition to the user's logcat output.
For short messages in a cluster, the contact photo was sometimes taller
than the actual bubble, leading to extra weird space. So instead we use
a container to hold the width of the cell, and set the avatar to be GONE
instead of INVISIBLE.
The previous way we were getting the next/previous record didn't take into
consideration that some records aren't in the cursor -- some are in the
fastRecords map. We now use the proper position to get the next/previous
message.
Apparently onAnimationEnd is not a reliable event on some Android
versions, so I've moved to instead using a simple postDelayed() that is
the same length as the animation.
The media size traditionally determines the bubble size, but the author
could make it wider, which would lead to rendering issues. In the case
of media attachments (images, videos, and shared contacts), we restrict
the width of the author name. When there's a number+profile name combo,
we split the space 50/50 between the two.
In particular, there were many issues with drawing corners.
Unfortunately, there's no pretty way to get masking working on every
Android version, so we have to switch back to using custom backgrounds
and then using multiple masking methods depending on Android version.
Also, I had to remove attr references in drawables. They crash on 4.x.
Unfortunately, there's apps out there that trigger contact changes
very frequently. Because we listen to the system for contact
changes to tell us when to sync, that could result in us sending
an abundance of contact syncs to linked desktop instances.
This throttles contact sync requests using the following methodology:
- By default, throttle contact syncs to 6 hrs while the app is
backgrounded.
- If a sync is throttled in the background, we set a dirty flag and
will execute the sync the next time the app is foregrounded.
- Syncs explicitly requested by desktop are never throttled.
The directory we were previously saving backups to on the external SD
card is actually deleted upon app uninstall and/or clearing the app's
data. There's also no reliable way to write to the root of an external
SD card (that isn't comically inconvenient), so for now it's safer if we
just move back to getting the regular 'ol standard external storage
directory (which is likely internal storage, despite its name).
Fixes#7845
For self-sends, we were never marking attachments as uploaded. I made is
so that happens now, but to prevent it for showing for already-sent
messages, we also don't show controls for self-send conversations.
This particularly helps with the bug where people who were newly added
to a group wouldn't receive an expiration timer until the first message
was sent.
Previously, contact shares would be displayed as "Media Message". Now
it'll show the same as it does in a notification, namely
"{contact-emoji} {contact-name}".
Previously, we were running this job in PushSendJob#onCanceled().
However, with the new retry logic, this won't happen for 24 hours.
Instead, we now schedule the job in PushSendJob#onRetry().
Previously, we retried based on a count. Now we've added the ability to
keep retrying for a specified time, using exponential backoff to
throttle attempts.
We never properly registered the ExpirationListener, meaning we were
relying on the wait-notify loop of ExpirationManager to delete things.
This normally works, but fails when your phone goes to sleep. So I
properly registered the receiver, and then added a failsafe to re-run
the ExpirationManager if we're about to render an expired message.
Fixes#7906
We have to make some changes, and it's gotten to the point where
maintaining it as a separate library is more hassle than it's worth,
especially with Google releasing WorkManager as the preferred job
scheduling library.
Previously, because apostrophes were 'banned' characters, searching for
them wouldn't work. That meant you couldn't find words like "I'm". Now
we just replace the apostrophe with a space and things "just work"
because of the nature of SQLite tokenization and prefix queries.