There was a bug around some emoji being marked as 'obsolete' and
therefore not being found.
I also made a change so that you can use skin variations of emoji and
still find emoji tagged with the default yellow version of it.
Fixes#9471
This wasn't actually being used in the User-Agent header. Instead, it
was used as the value for an X-Signal-Agent header. To avoid confusion,
I'm renaming this.
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.
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
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.
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
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.
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.
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.
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.
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
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.
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.
- 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.
This reverts commit 78fbfe40736dd8c9ccafb402aa7fc6921c1d4496.
We have turned on AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) now for API19.
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.
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.
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
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).
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>
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.
Android Q encounters massive slowdown when using contentUris for media.
Switching to fileUris (which we're already doing for the folder
thumbnail) gets us back to the expected performance level.
The crash happened because #getNextClosestEvent was called when
mmsDatabase was null, which would normally be impossible. However, it
seems implied that somehow #getNextClosestEvent was being called in the
parent constructor before the child class was fully initialized. That
would imply that the looper was called synchronously in some freak
scenario, but it's the only explanation. So I added a delay to the call
in the parent constructor.
```java
java.lang.NullPointerException:
at org.thoughtcrime.securesms.revealable.RevealableMessageManager.getNextClosestEvent (RevealableMessageManager.java:40)
at org.thoughtcrime.securesms.revealable.RevealableMessageManager.getNextClosestEvent (RevealableMessageManager.java:23)
at org.thoughtcrime.securesms.service.TimedEventManager.lambda$scheduleIfNecessary$1 (TimedEventManager.java:44)
at org.thoughtcrime.securesms.service.-$$Lambda$TimedEventManager$kZDO3F2WBQVtGx-SkAgEDt8jCeU.run (Unknown Source:2)
at android.os.Handler.handleCallback (Handler.java:873)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loop (Looper.java:193)
at android.os.HandlerThread.run (HandlerThread.java:65)
```
On phones with no SIM card, if you manage to enqueue a job with a
CellServiceConstraint, the previous check we were using to check if
there was cell service could hang indefinitely on some devices.
This changes it to a fast check, which all constraints should be.
There are a handful of devices that refuse to use our AesGcmProvider,
and as a result they would crash with AssertionErrors when downloading
avatars. Still haven't found why, but for now, probably best to stop
these devices from crashing, since it puts them in a crash loop, and the
app is still usable without avatars.
There appears to be a weird bucketing thing that happens on some
devices, where if you give them a resolution that's too small, it'll
default you to some potato resolution. So we just bumped it up to
1920x1920, and that seems to be working on my swath of devices.
If you gave the class an empty file, it would get back -1 for read(),
causing it to fall forever into negative values, never escaping the
existing conditions.
The side effect of this was weird corner cases where these infinite
reads could clog up threads, causing audio recordings to get blocked
and such.
Fixes#8898
There seems to be a bad implementation of Address parcelization that
pops up in certain scenarios. We can avoid it by just excluding it
from the parcel altogether.
CameraX was initializing Camera2 API stuff on API < 21, causing
crashes at boot. To handle this, we disable the default
ContentProvider initializer and initialize things ourselves for
appropriate API levels.
Due to support library bug, onActionItemClicked can be called after finish/onDestroyActionMode so we can check for that by checking if our reference to the action mode is still valid.
Fixes#8891
Previously, quotes could extend beyond the width of the link preview
banner image. Now quotes will be constrained to the size of the link
preview banner image.
* 4% of original pixels must be visible.
* The entire crop must be within the image.
* On release, try to scale crop area and image to fit if the crop is invalid.
* Undo to last valid position if that didn't work.
* Additionally, center thumbs now do not respect aspect ratio lock.
Due to a bug described in:
https://issuetracker.google.com/issues/110237303
Ordering of resources can be non-deterministic.
A comment on the issue indicates that this may be resolved in
Android Gradle Plugin 3.4. We should revisit when we update.
The recent switch to Python3 (2ccdf0e396) introduced a regression
that led to file content no longer being compared:
In compareEntries(), two generators/iterators are created:
sourceInfoList = filter(lambda sourceInfo: …, sourceZip.infolist())
destinationInfoList = filter(lambda destinationInfo: …, destinationZip.infolist())
Few lines later, those are exhausted:
if len(sourceInfoList) != len(destinationInfoList):
Yet another few lines later, the exhausted generator is used again:
for sourceEntryInfo in sourceInfoList:
… # <-- unreachable
This is caused by behavioral differences between Python2 and Python3:
user@z_signal:~$ python2
Python 2.7.13 (default, Sep 26 2018, 18:42:22)
[GCC 6.3.0 20170516] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> f = filter(lambda i: i % 2 == 0, [0, 1, 2, 3, 4, 5, 6])
>>> list(f)
[0, 2, 4, 6]
>>> list(f)
[0, 2, 4, 6]
>>>
user@z_signal:~$ python3
Python 3.5.3 (default, Sep 27 2018, 17:25:39)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> f = filter(lambda i: i % 2 == 0, [0, 1, 2, 3, 4, 5, 6])
>>> list(f)
[0, 2, 4, 6]
>>> list(f)
[]
>>>
- Check for permissions.
- Fix Welsh positional format.
- Remove UIThread restriction.
- Asynchronous method does not need to be restricted to UIThread and there is no StaticFieldLeak to suppress.
- Fix or Ignore New API errors.
- Reduce severity of some errors from L10N.
We observed IOExceptions loading the Contact Discovery IAS KeyStore. We will now throw an AssertionError upon any error
creating the IAS KeyStore, matching the behaviour for creation of the TrustStore used for the main Signal Service. NB: If
this assertion is hit, the user will not even be able to refresh their contacts with the old directory service.
We never make requests to non-whitelisted domains, but there were
situations where some links would redirect to non-whitelisted domains,
which would hit a final failsafe that resulted in a crash.
To prevent this, we detect bad redirects earlier and fail more
gracefully.
Fixes#8796
This will stop instances of the following from occuring in the logs
on SMS migration:
W/SQLiteCompiledSql: Releasing statement in a finalizer. Please ensure
that you explicitly call close() on your cursor: INSERT INTO sms
(address, person, date_sent, date, protocol, read, status, type,
reply_path_present,
net.sqlcipher.database.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
at net.sqlcipher.database.SQLiteCompiledSql.<init>(SQLiteCompiledSql.java:62)
at net.sqlcipher.database.SQLiteProgram.<init>(SQLiteProgram.java:109)
at net.sqlcipher.database.SQLiteStatement.<init>(SQLiteStatement.java:39)
at net.sqlcipher.database.SQLiteDatabase.compileStatement(SQLiteDatabase.java:1647)
at org.thoughtcrime.securesms.database.SmsDatabase.createInsertStatement(SmsDatabase.java:767)
at org.thoughtcrime.securesms.database.SmsMigrator.migrateConversation(SmsMigrator.java:166)
at org.thoughtcrime.securesms.database.SmsMigrator.migrateDatabase(SmsMigrator.java:210)
at org.thoughtcrime.securesms.service.ApplicationMigrationService$ImportRunnable.run(ApplicationMigrationService.java:159)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
We aren't closing Statement objects before the finalizer on those
objects runs. When the GC runs, we'll get warnings like the above
which alert us to the fact that these objects are being automatically
closed for us in the finalizer, but that this is suboptimal behavior.
If we leave too many Statement (or Cursor) objects to be closed in
their finalizers, when the GC runs, it'll take longer than 10 seconds
to close them all and Android will kill the app. This 10 second limit
is hardcoded and we can only try to avoid it. A crash will look like:
java.util.concurrent.TimeoutException: net.sqlcipher.database.SQLiteCompiledSql.finalize() timed out after 10 seconds
at java.lang.Object.wait(Native Method)
at java.lang.Thread.parkFor$(Thread.java:1220)
at sun.misc.Unsafe.park(Unsafe.java:299)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:810)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:844)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1173)
at java.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:196)
at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:257)
at net.sqlcipher.database.SQLiteDatabase.lock(SQLiteDatabase.java:553)
at net.sqlcipher.database.SQLiteCompiledSql.releaseSqlStatement(SQLiteCompiledSql.java:106)
at net.sqlcipher.database.SQLiteCompiledSql.finalize(SQLiteCompiledSql.java:152)
at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:202)
at java.lang.Daemons$FinalizerDaemon.run(Daemons.java:185)
at java.lang.Thread.run(Thread.java:818)
I was able to replicate the above crash consistently on a
Samsung Galaxy S7 edge when importing well over 100k SMS messages.
But as soon as I attached a debugger the crash did not persist. I
assume this is because of some VM-level interactions between the two
and did not investigate further after fixing it.
I do not have access to the stack trace for issue #7953 but this
could potentially resolve it. The crash is identical to that in #7477
but this patch is for SMS migration not restoring from a backup. I
was not able to replicate the crash on restoring a >100k message
backup.
It used to be that we let Android do the default behavior of
full-screening the EditText when in landscape, but honestly I
don't know who prefers that. So I've turned it off.
Fixes#8769
The new JobManager stuff created a table that had an
auto-incrementing ID, which was incorrectly being backed
up and restored, causing a crash. Now we skip it on both
import and export.
Some devices have a limit of 100 unique JobScheduler jobs.
Previously we allowed up to 1,000. Given that we just need
_some_ job running, I lowered the limit to 75 to give us
some head room.
- Eliminate the explicit spongycastle dependency. All access to
primitives is done through the JCE interfaces now, which allows
us to use a secure native-backed provider like conscrypt.
- Use conscrypt for our default security provider. This gives us
fast TLS 1.2 and 1.3 support on all devices, even before they
had platform support (like 4.4).
- Update minSdk to 18. Unfortunately the JCE interfaces for GCM
primitives are JDK 7+ (!) only, which became supported by Android
at 18.
We'll be updating minSdk to 19 in 4.37. This lets these users continue
to use the app, but they'll be warned with a persistent banner saying
that they can't receive updates.
If you navigated to the ConversationActivity again via some action (like
a shared contact invite) while searching, we don't get the toolbar close
event, and therefore the search nav would stay open. Now we just reset
it on newIntent() to be safe.
The way the highlight was done could get screwed up if you had multiple
whitespaces in a row. This particularly came up with messages with
multiple newlines.
`firebase_analytics_collection_enabled` is used for temporarily
enabling/disabling analytics.
We already use `firebase_analytics_collection_deactivated`, which is
used for permanently disabling analytics.
There were situations where adding/removing members from a group
would update the group member list, but the short string (the little
text listing the first couple members of the group) wouldn't be updated
until you left the screen and came back.
1. Due to ShareActivity having noHistory=true, it will already be
ditched when you leave the activity.
2. We only need to truly finish() here if we've dropped the underlying
media.
Fixes#8591
Prevent users from trying to send videos that exceed the size limit.
Also, this commit properly populates height/width on media shared into
the app.
Fixes#8573
It didn't re-measure when pulling an item from the cache, screwing stuff
up after a phone rotation. Had a workaround for it for specific screens,
but this fixes the problem at the source.
Fixes#8583
"Understood" or "Got it" is a way of dismissing a splash screen of notification without any change that is applies agreeing to anything.
It replaces "OK" which was sometimes misinterpreted as "I am OK with what I just read".
There's odd corner cases where channels can be duplicated. This commit
adds some hard checks where we trim any dead channels, and unset any
notification channels from recipients whose notification channel isn't
present in the system settings.
`DEFAULT_CHANNEL_ID` is a String, but `channel` is a NotificationChannel. Equals will therefore always return `false`. I think my fix (using `getId()`) is what was intended.
TreeSets are annoying. contains() is calculated with the comparator,
which can lead to some weird bugs. Made sure the comparator didn't think
two items with the same date were identical.
Also fixed stableId generation to avoid any potential weirdness there.
Update our media send flow to allow users to send multiple images/videos
at once. This change includes:
- New in-app media picker flow.
- Ability to caption images and videos.
- Image editing tools are made more prominent in the flow.
- Some fixes to the image editing tools.
Google removed a bunch of binaries from jcenter that they shouldn't
have, breaking everyone's builds. So now we have manually add repos for
the missing binaries in the meantime.
On some devices, pausing+resuming (or seeking) would restart playback
from the beginning, but show a progress bar further up. This seems to
have been caused by same race condition-y thing where we were seeking
multiple times in rapid succession. Now we'll only play once, and things
seem to be fine now.
Also removed usage of some deprecated methods.
Fixes#8432
The Android animators were getting out of sync when frames were dropped
(despite my best efforts), so now we just manually render each animation
frame as a function of time, so it never gets screwed up.
Fixes#8388
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
We updated our build tools and stuff, so we have to update the
Dockerfile. Took this opportunity to also update the version of
Ubuntu we were using as the base.
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
If the user has an external SD card set as their default storage
(notably on a Huawei device, like the Huawei Mate 10 Lite), then
PersistentBlobProvider will try to write a file to the SD card, but
would fail to generate a URI for it due to us missing a line in our
FileProvider setup. This just adds that missing entry.
Special thanks to @aleb2000 for digging into this!
Fixes#8144Fixes#7726
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.
Translation completion >= 90%, with the exception of Irish (80%), but they've been waiting for a rather long time.
Added:
- Irish
- Kurdish
- Telugu
- Ukrainian
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.
Previously, we didn't support highlighting search results that had
tokens in the middle of the matches, which is a possibility with FTS.
Now we do more robust highlighting, as well as highlight matches in
phone numbers.
Previously, we made each full-text search query a single prefix query.
That means that the query "do c" would turn into "do c*". That means it
would match "do cat" but not "dog cat".
Now, we make each token a prefix query. So "do c" would turn into
"do* c*". That means it would match both "do cat" and "dog cat".
Previously, if a message disappeared while looking at it in the search
results, it'd still stick around. Now they'll disappear from the results
in real-time.
1) There was an issue where we wouldn't auto-download group syncs.
2) There was another issue where we didn't show the download controls
for messages you sent yourself.
Fixed#7920
There was an issue where we were backing up group receipts and attachments
that were for expiring messages (which are already excluded from the backup).
This commit excludes these items from the backup, and for backups made
before this change, this commit also deletes these invalid entries at
the end of the restore process.
We also do a little database migration to cleanup any bad state that may
have been imported in the past.
Turns out that there's some weird quasi-state when you come out of
airplane mode, that if you do an InetAdress lookup, it returns some
weird IPv6-looking garbage address. Going to retry in that scenario
instead of assuming an outage.
Previously, if an operation failed, we set the result to "null".
However, this was a mistake. Setting the result at all assumes success.
Instead, we need to set an exception so the ListenableFuture knows that
the operation failed.
A variety of improvements to the image editor, such as:
- New, fullscreen styling
- Smoother lines
- Better text and sticker handling
- Improved color picker with a history pallette
- New highlighter tool
Previously, SQLCipher's memory usage would grow indefinitely, up until
it hit the end of the cursor. We've now switched to a release where the
memory used by the cursor can be bounded.
If a user is upgrading to use the SQLCipher database (which happened
back in 4.16, so this only applies to relatively dormant users who are
just getting back into the app) and received a new "user X joind signal"
message, then it could screw up the migration. So we're just dropping
these notifications that happen in this narrow window.
The sticky header cache was keeping views across rotations, causing them
to render incorrectly afterwards. I added a method to invalidate the
header layouts after rotation.
Fixes#7890.
First, FTS index contents do not need to be exported. They will be recreated naturally.
Second, we can't export the secret FTS tables, or SQLite will think it's corrupted.
Fixed an issue where jumbomoji were not properly being rendered
when using system emoji. Also fixed an issue where the text
content wasn't properly being recalculated when the view is
resized.
Fixes#7875
1. Switch to using default text rendering if there's no emoji present in
the string.
2. Reduce redudant redraws by skipping of setText() calls for identical
strings.
Together, these two changes should reduce the vast majority of
flickering we see with EmojiTextView ellipsizing.
I think I was initially lured into searching by rank because it gives
the illusion of providing the "best match". However, in practice, FTS
never gives back "bad" matches with low ranks -- all of the results it
returns will contain your query in some form (most commonly a direct
substring, but they do take some liberties if you have multiple tokens
in your queries). Given that, in general, more recent search results are
in fact more relevant, we can sort by date exclusively and get a better
ordering overall.
If a search result snippet spans two lines, we only show the first line.
For the purpose of display, we first remove all newlines in order to
make the full snippet visible.
Previously, we'd always use the recipient of the message record, which
was incorrect for messages sent to groups. Now we always use the
recipient for the matching thread record.
Fixes#7823
Glide will use the dimensions of the target ImageView as the dimensions
for the image it's loading. This caused problems in the case of
ThumbnailView, as we were constantly changing the ImageView dimensions,
meaning Glide may not have the most recent values (it may be called in
between measure calls, for instance).
To solve this, we now will always override the default image dimensions
when we load an image. If no dimensions are present, we will default to
the layout_width and layout_height of the ThumbnailView.
Fixes#7810
Using the singleLine attribute will make the TextView report that the
lineCount is always 1, regardless of actual text length. This breaks our
manual ellipsize calculation. Because you can't actually read the
singleLine attribute at runtime, I've switched relevant usages of
singleLine to use maxLines=1 (relevant usages are EmojiTextViews where
singleLine was set and ellipsize was set to 'end').
Fixes#7744
Notifications for replies will no longer display as a "Media Message" if
they do not contain media. Instead, they will just contain the reply
text.
Fixes#7798
Sending shared contacts isn't backwards-compatible, so we want to have a
few releases where receiving is enabled, but not sending. That way, when
we enable sending, most users should be able to properly receive the
shared contact messages.
When you share a vCard from an external app (like the Contacts app) into
Signal, we'll now convert it to a pretty Shared Contact message and
allow you to choose which fields of the contact you wish to send.
The "contact" option in the attachments tray now brings you through an
optimized contact sharing flow, allowing you to select specific fields
to share. The contact is then presented as a special message type,
allowing you to interact with the card to add the contact to your system
contacts, invite them to signal, initiate a signal message, etc.
There's a chance that the AsyncTask that retrieves a quoted message's
position could finish after the fragment is detached, which would cause
a crash. I've changed it so if this case occurs, the result is ignored.
Also, I noticed that when searching the message table, if a quote can't
be found, we'd end up traversing the entire table. To prevent this from
taking forever on large message tables, I've limited it to searchin only
what is currently present in the adapter.
Fixes#7756
Did a refactor to better organize the camera flipping code. Also, I
wanted to make sure we handle the cases where the user doesn't have two
cameras (or no cameras, for that matter). In these cases, we just don't
show the appropriate buttons.
Previously, quotes were not saved to drafts, meaning they would be lost
when leaving the conversation or app. Now, a QuoteId (which represents
the necessary data to restore the QuoteModel) is serialized and stored
in the DraftDatabase.
Fixes#7716Closes#7729
Unfortunately, the change wasn't as simple as just switching to use our
EmojiTextView. That view only supported single-line text. I added
support for multi-line text.
Fixes#7704.
We now check if _any_ text is selected when doing a batch selection
to determine if we should show the copy option. Also, previously it
was putting in empty lines for messages that don't have any text. I
changed it so empty messages have no effect on the text that is copied.
Fixes#7472
Currently, if you're searching for a contact to start a conversation
with or send a share to (via the Android sharing system), groups do not
appear. With this change, groups will now appear when searching, located
under their own heading.
Fixes#7202.
Closes#7577
In landscape, you'd see that the tabs were a different color from the
toolbar. This has been corrected so they're all the same color now.
Fixes#7578Closes#7579
Previously, we were always rendering images as squares. Instead of doing
that, we now render them as close to true-to-size as possible (within
reasonable min/max width/height boundaries).
Strip all EXIF metadata from all JPEGs by re-encoding the JPEG. This
will keep all of the necessary visual effects of the tags (by encoding
them directly in the image data) while stripped the EXIF tags
themselves.
It is now possible to batch-delete media in the "media overview" screen.
You can long press to enter multi-select mode. Then a delete button
appears on the menu bar. After pressing delete, you will get a
confirmation, and if the user confirms, the items will delete while a
progres dialog shows.
When viewing a media in the media preview, you can delete it by pressing
a delete button on the action bar. It will then ask you to confirm your
choice. If you confirm, it will delete the attachment from the database
and from disk. If it was the only attachment for that message, the
message itself will also be deleted.
In a number of locations in the code, there were conversions of message
expiration times from seconds to milliseconds, and then assigned to `long`
contexts. However these conversions were being done as integer multiplication
rather than long multiplication, meaning that there was a potential for
overflows.
Specifically, the maximum value that could be represented before overflowing
was (2^31 / 1000 / 60 / 60 / 24) days = 24.8 days (< 1 month). Luckily the
current allowed timeouts are all less than that value, but this fix would
remove the artificial restriction, effectively allowing values of 1000x greater
(68 years), at least for android.
Related #5775Closes#7338
1. Replace custom ringtone picker with system Intent, since we
don't need it anymore. Fixes#7174
2. Make sure 'silent' ringtone selection is stored appropriately
Fixes#7115Closes#7141
3. Replace any existing file:// notification URIs with the system
default Fixes#7234
1) Move contact URI, contact photo URI, and custom label
into recipient database, so there are no longer any
contact DB queries during Recipient object loading.
2) Use a SoftHashMap so that any referenced Recipient objects
can't get kicked out of the cache.
3) Don't load Recipient objects through the provider during sync.
This was a super expensive thing to do, and blew up the cache.
4) Only apply changes to Recipient objects during sync if they
are in the cache. Otherwise, there should be no outstanding
references, and the changes are fine going exclusively to
the DB.
The whole recipient pipeline needs to be changed more subsantially,
particularly given the way directory discovery works with it. This
will temporarily solve the problem though.
1) The "obsolete" images like "swimmer" need to alias to
"man_swimming" so that they can be rendered correctly.
2) There are a whole bunch of emoji-data elements
(like white_frowning_face) that have "unified" code points which
have changed to include a "terminator."
Fixes#7212
The Android v4 and v7 support libraries now only support a minSdk
of v14. This means that they are both essentially a v14 support
library now.
In order to bump compileSdk to 26, we'll have to update the support
library, which will break < v14 compatibility. Android is
essentially forcing all applications to break compatibility with
devices older than API 14.
// FREEBIE
Expiring message timers could end up leaking references and
executing work even after their conversation item was no longer
visible
Maybe fixes#6898
// FREEBIE
Don't use a cached recipient if we have a prefetched recipient
detail object and the cached recipient is still in progress
and without a name
// FREEBIE
This resolves#6374 where the character set is set to
`CharacterSets.MIMENAME_ANY_CHARSET` but the character set being
used is _actually_ UTF-8.
Fixes#6374Closes#6892
Eliminate the concept of 'Recipients' (plural). There is now just
a 'Recipient', which contains an Address that is either an individual
or a group ID.
MMS groups now exist as part of the group database, just like push
groups.
// FREEBIE
There's not a great way for me to know which of them is the "real"
entry, which means that I could be deleting the wrong one. In the
case of recipient "preferences," it's hopefully not a huge loss,
and there aren't any other great options.
Fixes#6838
// FREEBIE
This was a holdover from Signal's origins as a pure SMS app.
It causes problems, depends on undefined device specific behavior,
and should no longer be necessary now that we have all the
information we need to E164 all numbers.
// FREEBIE
This commit adds the contact name and the readable date (and time) to
the plaintext export of every message. That's because that is how SMS
Backup and Restore does it, so this commit makes Signal more compatible.
Closes#6452
// FREEBIE
This could be a sync message, delivery receipt, or some other
message that isn't user-visible. The push notification content
would need to indicate whether that's the case in order to be
able to accurately display a notification
// FREEBIE
Disabling OpenSL ES seems to make the hardware AEC "work" on
devices where it was previously causing problems.
Using the WebRTC-based software AEC *without* OpenSL ES seems to
be causing new problems.
Fixes#6737
Related #6432
Related #6241
// FREEBIE
1) Prefetch identity keys when possible
2) Always accept prefetched keys or keys from incoming messages
3) Block sending only if it's a recent change, or if always
block is enabled
// FREEBIE
1) Remove all our PDU code and switch to the PDU code from the
klinker library
2) Switch to using the system Lollipop MMS library by default,
and falling back to our own custom library if that fails.
3) Format SMIL differently, using code from klinker instead of
what we've pieced together.
4) Pull per-carrier MMS media constraints from the XML config
files in the klinker library, instead of hardcoding it at 280kb.
Hopefully this is an improvement, but given that MMS is involved,
it will probably make things worse instead.
If Camera2Enumerator.isSupported() throws, consider Camera2Enumerator to
not be supported, log the Throwable, and use Camera1Enumerator instead.
Before this patch, an exception thrown by Camera2Enumerator.isSupported
would crash any Signal call (even if video was not enabled).
Fixes#6537
// FREEBIE
1) Remove phantom padding on left margin for all fragments
2) Move preferences around slightly
3) Add some card separators and style led list pref
// FREEBIE
<!-- This is a bug report template. By following the instructions below and filling out the sections with your information, you will help the developers to get all the necessary data to fix your issue.
<!-- This is a bug report template. By following the instructions below and filling out the sections with your information, you will help the developers get all the necessary data to fix your issue.
You can also preview your report before submitting it. You may remove sections that aren't relevant to your particular case.
Before we begin, please note that this tracker is only for issues, not questions or comments.
Before we begin, please note that this tracker is only for issues. It is not for questions, comments, or feature requests.
If you are looking for support, please see our support center instead:
https://support.whispersystems.org/
or email support@whispersystems.org
If you would like to discuss a new feature or submit suggestions, please visit the community forum:
https://community.signalusers.org
Let's begin with a checklist: replace the empty checkboxes [ ] below with checked ones [x] accordingly -->
If you are looking for support, please visit our support center:
https://support.signal.org/
or email support@signal.org
I have:
- [ ] searched open and closed issues for duplicates
<!-- You can remove this first section if you have contributed before -->
### First time contributor checklist
<!-- replace the empty checkboxes [ ] below with checked ones [x] accordingly -->
- [ ] I have read [how to contribute](https://github.com/WhisperSystems/Signal-Android/blob/master/CONTRIBUTING.md) to this project
- [ ] I have read [how to contribute](https://github.com/signalapp/Signal-Android/blob/master/CONTRIBUTING.md) to this project
- [ ] I have signed the [Contributor License Agreement](https://whispersystems.org/cla/)
### Contributor checklist
<!-- replace the empty checkboxes [ ] below with checked ones [x] accordingly -->
- [ ] I am following the [Code Style Guidelines](https://github.com/WhisperSystems/Signal-Android/wiki/Code-Style-Guidelines)
- [ ] I am following the [Code Style Guidelines](https://github.com/signalapp/Signal-Android/wiki/Code-Style-Guidelines)
- [ ] I have tested my contribution on these devices:
* Device A, Android X.Y.Z
* Device B, Android Z.Y
* Virtual device W, Android Y.Y.Z
- [ ] My contribution is fully baked and ready to be merged as is
- [ ] I ensure that all the open issues my contribution fixes are mentioned in the commit message of my first commit using the `Fixes #1234` [syntax](https://help.github.com/articles/closing-issues-via-commit-messages/)
- [ ] I have made the choice whether I want the [BitHub reward](https://github.com/WhisperSystems/Signal-Android/wiki/BitHub-Rewards) or not by omitting or adding the word `FREEBIE` in the commit message of my first commit
2. Make sure you have the [Android SDK](https://developer.android.com/sdk/index.html) installed.
3. Ensure that the following packages are installed from the Android SDK manager:
* Android SDK Build Tools (see buildToolsVersion in build.gradle)
* SDK Platform (API level 22)
* Android Support Repository
* Google Repository
4. Create a local.properties file at the root of your source checkout and add an sdk.dir entry to it. For example:
sdk.dir=/Application/android-sdk-macosx
5. Execute Gradle:
./gradlew build
Visual assets
----------------------
Source assets tend to be large binary blobs, which are best stored outside of git repositories. We host ours in a [Pixelapse repository](https://www.pixelapse.com/openwhispersystems/projects/signal-android/). Some source files are SVGs that can be auto-colored and sized using a tool like [android-res-utils](https://github.com/sebkur/android-res-utils).
Sample command for generating our audio placeholder image:
[Android Studio](https://developer.android.com/sdk/installing/studio.html) is the recommended development environment.
1. Install Android Studio.
2. Open Android Studio. On a new installation, the Quickstart panel will appear. If you have open projects, close them using "File > Close Project" to see the Quickstart panel.
3. From the Quickstart panel, choose "Configure" then "SDK Manager".
4. In the SDK Tools tab of the SDK Manager, make sure that the "Android Support Repository" is installed, and that the latest "Android SDK build-tools" are installed. Click "OK" to return to the Quickstart panel.
5. From the Quickstart panel, choose "Checkout from Version Control" then "git".
6. Paste the URL for the Signal-Android project when prompted (https://github.com/WhisperSystems/Signal-Android.git).
7. Android studio should detect the presence of a project file and ask you whether to open it. Click "yes".
9. Default config options should be good enough.
9. Project initialisation and build should proceed.
Contributing code
-----------------
Code contributions should be sent via github as pull requests, from feature branches [as explained here](https://help.github.com/articles/using-pull-requests).
Mailing list
------------
Development discussion happens on the whispersystems mailing list.
Thank you for deciding to help this project! If you have contributed to other open source projects before please note that some conventions here might be a bit different than what you are used to. Reading this document will save you, other contributors and the developers time.
Thank you for supporting Signal and looking for ways to help. Please note that some conventions here might be a bit different than what you are used to, even if you have contributed to other open source projects before. Reading this document will help you save time and work effectively with the developers and other contributors.
## Development Ideology
@@ -9,80 +9,81 @@ Truths which we believe to be self-evident:
1.**The answer is not more options.** If you feel compelled to add a preference that's exposed to the user, it's very possible you've made a wrong turn somewhere.
1.**The user doesn't know what a key is.** We need to minimize the points at which a user is exposed to this sort of terminology as extremely as possible.
1.**There are no power users.** The idea that some users "understand" concepts better than others has proven to be, for the most part, false. If anything, "power users" are more dangerous than the rest, and we should avoid exposing dangerous functionality to them.
1.**There are no power users.** The idea that some users "understand" concepts better than others has proven to be, for the most part, false. If anything, "power users" are more dangerous than the rest, and we should avoid exposing dangerous functionality to them.
1.**If it's "like PGP," it's wrong.** PGP is our guide for what not to do.
1.**It's an asynchronous world.** Be wary of anything that is anti-asynchronous: ACKs, protocol confirmations, or any protocol-level "advisory" message.
1.**There is no such thing as time.** Protocol ideas that require synchronized clocks are doomed to failure.
1.**There is no such thing as time.** Protocol ideas that require synchronized clocks are doomed to failure.
## Translations
Please do not submit issues or pull requests for translation fixes. Anyone can update the translations in [Transifex](https://www.transifex.com/projects/p/signal-android/). Please submit your corrections there.
Thanks to a dedicated community of volunteer translators, Signal is now available in more than one hundred languages. We use Transifex to manage our translation efforts, not GitHub. Any suggestions, corrections, or new translations should be submitted to the [Signal localization project for Android](https://www.transifex.com/signalapp/signal-android/).
## Issues
### Useful bug reports
1. Please search both open and closed issues first to make sure your issue is not a duplicate.
1. Read the [Submitting useful bug reports guide](https://github.com/WhisperSystems/Signal-Android/wiki/Submitting-useful-bug-reports) before posting a bug.
1. Please search both open and closed issues to make sure your bug report is not a duplicate.
1. Read the [guide to submitting useful bug reports](https://github.com/signalapp/Signal-Android/wiki/Submitting-useful-bug-reports) before posting a bug.
### Issue tracker is for bugs
The main purpose of this issue tracker is to track bugs for the Android client. Relevant, concise and to the point comments that help to solve the issue are very welcome.
### The issue tracker is for bugs, not feature requests
The GitHub issue tracker is not used for feature requests, but new ideas can be submitted and discussed on the [community forum](https://community.signalusers.org/c/feature-requests). The purpose of this issue tracker is to track bugs in the Android client. Bug reports should only be submitted for existing functionality that does not work as intended. Comments that are relevant and concise will help the developers solve issues more quickly.
##### Send support questions to support
Please do **not** ask support questions at the issue tracker. We want to help you using Signal and we have created our support system just for that. You can reach support by sending email to support@whispersystems.org or by going to our [Support Center](http://support.whispersystems.org). You can also search for existing troubleshooting articles at the [Support Center](http://support.whispersystems.org).
### Send support questions to support
You can reach support by sending an email to support@signal.org or by visiting the [Signal Support Center](https://support.signal.org/) where you can also search for existing troubleshooting articles and find answers to frequently asked questions. Please do not post support questions on the GitHub issue tracker.
##### Not a discussion forum
Please do **not** use this issue tracker as a discussion forum. Discussion related to the bug in question should of course go to the issue itself. However other discussion should take place at the [community forum](https://whispersystems.discoursehosting.net). You can use that forum to discuss any Signal related topics or to just hang out with your fellow users.
### GitHub is not a generic discussion forum
Conversations about open bug reports belong here. However, all other discussions should take place on the [community forum](https://community.signalusers.org). You can use the community forum to discuss anything that is related to Signal or to hang out with your fellow users in the "Off Topic" category.
### Don't bump issues
Every time someone comments on an issue, GitHub sends email to [everyone who is watching](https://github.com/WhisperSystems/Signal-Android/watchers) the repository (currently around 500 people). Thus bumping issues with :+1:s, _me toos_or asking for updates generates a lot of unnecessary email notifications. Moreover bumping an issue does not help solve it. Please be respectful of everyone's time and only comment if you have relevant new information to add.
Every time someone comments on an issue, GitHub sends an email to [hundreds of people](https://github.com/signalapp/Signal-Android/watchers). Bumping issues with a "+1" (or asking for updates) generates a lot of unnecessary email notifications and does not help anyone solve the issue any faster. Please be respectful of everyone's time and only comment when you have new information to add.
### Open issues
#### If it's open it's tracked
Have you followed all the points in the [Submitting useful bug reports guide](https://github.com/WhisperSystems/Signal-Android/wiki/Submitting-useful-bug-reports) but nobody has commented on your issue? Is there no milestone or person assigned to it? Don't worry, the developers read every issue and if it's open it means it's tracked and taken into account. It might just take time as other issues have higher priority. And remember that this is an open source project: Everyone is encouraged to take an active role in fixing open issues.
#### If it's open, it's tracked
The developers read every issue, but high-priority bugs or features can take precedence over others. Signal is an open source project, and everyone is encouraged to play an active role in diagnosing and fixing open issues.
### Closed issues
#### "My issue was closed without giving a reason!"
Please understand that writing detailed explanations every time for every issue someone comes up with takes time. Sometimes a reason has been posted earlier to another related issue which you can search for. It's also possible that your issue was not in line with the guidelines of the project (see especially the [Development Ideology](https://github.com/WhisperSystems/Signal-Android/blob/master/CONTRIBUTING.md#development-ideology)), or it was decided that the issue is not something that Signal should do at this time.
Although we do our best, writing detailed explanations for every issue can be time consuming, and the topic also might have been covered previously in other related issues.
## Pull requests
### Sign the Contributor Licence Agreement (CLA)
You need to sign our CLA before your pull request can be merged. You can sign it at: https://whispersystems.org/cla/
### Smaller is better
Big changes are significantly less likely to be accepted. Large features often require protocol modifications and necessitate a staged rollout process that is coordinated across millions of users on multiple platforms (Android, iOS, and Desktop).
Try not to take on too much at once. As a first-time contributor, we recommend starting with small and simple PRs in order to become familiar with the codebase. Most of the work should go into discovering which three lines need to change rather than writing the code.
### Sign the Contributor License Agreement (CLA)
You will need to [sign our CLA](https://signal.org/cla/) before your pull request can be merged.
### Follow the Code Style Guidelines
Before submitting a pull request please check that your code adheres to the [Code Style Guidelines](https://github.com/WhisperSystems/Signal-Android/wiki/Code-Style-Guidelines).
Ensure that your code adheres to the [Code Style Guidelines](https://github.com/signalapp/Signal-Android/wiki/Code-Style-Guidelines) before submitting a pull request.
### Submit only complete PRs and test them
Please do not submit pull requests that are still a work in progress. Pull requests should be ready for a merge when you submit them. Also please do not submit pull requests that you have not tested.
### Smaller is better
Please do not try to change too much at once. Big changes are less likely to be merged. If you are a first time contributor start with small and simple PRs to get to know the codebase.
### Submit finished and well-tested pull requests
Please do not submit pull requests that are still a work in progress. Pull requests should be thoroughly tested and ready to merge before they are submitted.
### Merging can sometimes take a while
If your pull request follows all the advice above but still has not been merged it usually means the developers haven't simply had the time to review it yet. We understand that this might feel frustrating. We are sorry!
### Bithub
Accepted pull requests will be rewarded with Bitcoins! After your pull request has been merged you will automatically receive an email to the address you have specified as your Git commit email. Follow the instructions in the email to claim your coins. If you wish to submit your contribution for free please add the word `FREEBIE` in your Git commit message. You may wish to explore some previously merged commits to see how it all works.
If your pull request follows all of the advice above but still has not been merged, this usually means that the developers haven't had time to review it yet. We understand that this might feel frustrating, and we apologize. The Signal team is still small, but [we are hiring](https://signal.org/workworkwork/).
## How can I contribute?
Anyone can help by
-advising new people about the guidelines of this project
-redirecting support questions to support@whispersystems.org and the [support site](https://support.whispersystems.org)
-redirecting non-bug related discussions to the [community forum](https://whispersystems.discoursehosting.net)
-improving documentation in the [wiki](https://github.com/WhisperSystems/Signal-Android/wiki)
- finding solutions to open issues and posting relevant findings as comments
-submitting pull requests
-testing other people's pull requests
-spreading the joy of Signal to your friends and family
-donating money to our [BitHub](https://www.coinbase.com/checkouts/51dac699e660a4d773216b5ad94d6a0b) or through the [Freedom of the Press Foundation's donation page](https://freedom.press/crowdfunding/signal/)
There are several other ways to get involved:
*Help new users learn about Signal.
*Redirect support questions to support@signal.org and the [Signal Support Center](https://support.signal.org/).
*Redirect non-bug discussions to the [community forum](https://community.signalusers.org).
*Improve documentation in the [wiki](https://github.com/signalapp/Signal-Android/wiki).
*Join the community of volunteer translators on Transifex:
@@ -6,12 +6,12 @@ Signal uses your phone's data connection (WiFi/3G/4G) to communicate securely, o
Currently available on the Play store.
<a href="https://play.google.com/store/apps/details?id=org.thoughtcrime.securesms&utm_source=global_co&utm_medium=prtnr&utm_content=Mar2515&utm_campaign=PartBadge&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1"><img alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/generic/en-play-badge.png" height=36px/></a>
<a href='https://play.google.com/store/apps/details?id=org.thoughtcrime.securesms&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png' height='80px'/></a>
## Contributing Bug reports
We use GitHub for bug tracking. Please search the existing issues for your bug and create a new one if the issue is not yet tracked!
Instructions on how to setup your development environment and build Signal can be found in [BUILDING.md](https://github.com/WhisperSystems/Signal-Android/blob/master/BUILDING.md).
If you're new to the Signal codebase, we recommend going through our issues and picking out a simple bug to fix (check the "easy" label in our issues) in order to get yourself familiar. Also please have a look at the [CONTRIBUTING.md](https://github.com/WhisperSystems/Signal-Android/blob/master/CONTRIBUTING.md), that might answer some of your questions.
If you're new to the Signal codebase, we recommend going through our issues and picking out a simple bug to fix (check the "easy" label in our issues) in order to get yourself familiar. Also please have a look at the [CONTRIBUTING.md](https://github.com/signalapp/Signal-Android/blob/master/CONTRIBUTING.md), that might answer some of your questions.
For larger changes and feature ideas, we ask that you propose it on the [unofficial Community Forum](https://whispersystems.discoursehosting.net) for a high-level discussion with the wider community before implementation.
This repository is set up with [BitHub](https://whispersystems.org/blog/bithub/), so you can make money for committing to Signal. The current BitHub price for an accepted pull request is:
For larger changes and feature ideas, we ask that you propose it on the [unofficial Community Forum](https://community.signalusers.org) for a high-level discussion with the wider community before implementation.
## Contributing Ideas
Have something you want to say about Open Whisper Systems projects or want to be part of the conversation? Get involved in the [community forum](https://whispersystems.discoursehosting.net).
You can add funds to BitHub to directly help further development efforts.
Have something you want to say about Open Whisper Systems projects or want to be part of the conversation? Get involved in the [community forum](https://community.signalusers.org).
Help
====
## Support
For troubleshooting and questions, please visit our support center!
Note that the instructions above use a pre-built Signal Docker image from [Docker Hub](https://hub.docker.com/u/whispersystems/). If you wish to compile the image yourself, continue reading the longer version below.
***
## Introduction
Since version 3.15.0 Signal for Android has supported reproducible builds. This is achieved by replicating the build environment as a Docker image. You'll need to build the image, run a container instance of it, compile Signal inside the container and finally compare the resulted APK to the APK that is distributed in the Google Play Store.
The command line parts in this guide are written for Linux but with some little modifications you can adapt them to macOS (OS X) and Windows. In the following sections we will use `3.15.2` as an example Signal version. You'll just need to replace all occurrences of `3.15.2` with the version number you are about to verify.
## Setting up directories
First let's create a new directory for this whole reproducible builds project. In your home folder (`~`), create a new directory called `reproducible-signal`.
```
user@host:$ mkdir ~/reproducible-signal
```
Next create another directory inside `reproducible-signal` called `apk-from-google-play-store`.
The output will tell you where the Signal APK is located in your device. (In this example the path is `/data/app/org.thoughtcrime.securesms-aWRzcGlzcG9wZA==/base.apk`)
Now using this information, pull the APK from your device to the `reproducible-signal/apk-from-google-play-store` directory you created before:
We will use this APK in the final part when we compare it with the self-built APK from GitHub.
## Identifying the ABI
Since v4.37.0, the APKs have been split by ABI, the CPU architecture of the target device. Google play will serve the correct one to you for your device.
To identify which ABIs the google play APK supports, we can look inside the APK, which is just a zip file:
As there is just one sub directory of `lib/` called `armeabi-v7a`, that is your ABI. Make a note of that for later. If you see more than one subdirectory of `lib/`:
Install Docker by following the instructions for your platform at https://docs.docker.com/engine/installation/
Your platform might also have its own preferred way of installing Docker. E.g. Ubuntu has its own Docker package (`docker.io`) if you do not want to follow Docker's instructions.
In the following sections we will assume that your Docker installation works without issues. So after installing, please make sure that everything is running smoothly before continuing.
## Building a Docker image for Signal
#### Grabbing the `Dockerfile`
First you will need the `Dockerfile` for Signal Android. It comes bundled with Signal's source code. The `Dockerfile` contains instructions on how to automatically build a Docker image for Signal. You just need to run it and it builds itself.
Download the `Dockerfile` to the `image-build-context` directory.
Note that the `Dockerfile` is specific to the Signal version you want to compare to. Again you have to adjust the URL above to match the right version. (Though sometimes the file might not be up to date, see the [Troubleshooting section](#troubleshooting))
#### Building the image
Now we have everything we need to build the Docker image for Signal. Go to the `image-build-context` directory:
```
user@host:$ cd ~/reproducible-signal/image-build-context
```
And list the contents.
```
user@host:$ ls
```
The output should look like this:
```
Dockerfile_v3.15.2
```
Now in this directory build the image using `Dockerfile_v3.15.2`:
Before you can compile, you **must** ensure that you are at the right commit. In other words you **must** checkout the version you wish to verify (here we are verifying 3.15.2):
After the build has completed successfully we can finally compare if the APKs match. For the comparison we need of course the Google Play Store version of Signal APK which you copied to the `apk-from-google-play-store` directory in the beginning of this guide. Because we used that directory as a `--volume` parameter for our container, we can see all the files in that directory within our container.
So now we can compare the APKs using the `apkdiff.py` tool.
The above build step produced several APKs, one for each supported ABI and one universal one. You will need to determine the correct APK to compare.
Currently, the most common ABI is `armeabi-v7a`. Other options at this time include `x86` and `universal`. In the future it will also include 64-bit options, such as `x86_64` and `arm64-v8a`.
See [Identifying the ABI](#identifying-the-abi) above if you don't know the ABI of your play store APK.
Once you have determined the ABI, add an `abi` environment variable. For example, suppose we determine that `armeabi-v7a` is the ABI google play has served:
If you get `APKs match!`, you have successfully verified that the Google Play release matches with your own self-built version of Signal. Congratulations! Your APKs are a match made in heaven! :sparkles:
If you get `APKs don't match!`, you did something wrong in the previous steps. See the [Troubleshooting section](#troubleshooting) for more info.
## Comparing next time
If the build environment (i.e. `Dockerfile`) has not changed, you don't need to build the image again to verify a newer APK. You can just [run the container again](#compiling-signal-inside-a-container).
## Troubleshooting
If you cannot get things to work, please do not open an issue or comment on an existing issue at GitHub. Instead, ask for help at https://community.signalusers.org/c/development
Some common issues why things may not work:
- some pinned packages in the `Dockerfile` are not available anymore and building of the Docker image fails
- the Android packages in the Docker image are outdated and compiling Signal fails
- you built the Docker image with a wrong version of the `Dockerfile`
- you didn't checkout the correct Signal version tag with Git before compiling
- the ABI you selected is not the correct ABI, particularly if you see an error along the lines of `Sorted manifests don't match, lib/x86/libcurve25519.so vs lib/armeabi-v7a/libcurve25519.so`.
- this guide is outdated
- you are in a dream
- if you run into this issue: https://issuetracker.google.com/issues/110237303 try to add `resources.arsc` to the list of ignored files and compare again
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<SubscriptionInfo> list = subscriptionManager.getActiveSubscriptionInfoList();"
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.