2014-07-25 22:14:29 +00:00
/ *
* Copyright ( C ) 2013 Open Whisper Systems
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
package org.thoughtcrime.securesms ;
2017-12-22 00:37:07 +00:00
import android.annotation.SuppressLint ;
2018-07-07 00:28:58 +00:00
import android.arch.lifecycle.DefaultLifecycleObserver ;
import android.arch.lifecycle.LifecycleOwner ;
import android.arch.lifecycle.ProcessLifecycleOwner ;
2019-11-21 05:31:01 +00:00
import android.content.ComponentName ;
2014-07-25 22:14:29 +00:00
import android.content.Context ;
2019-11-21 05:31:01 +00:00
import android.content.Intent ;
2019-09-10 06:49:17 +00:00
import android.database.ContentObserver ;
2017-01-11 23:37:51 +00:00
import android.os.AsyncTask ;
2017-02-14 06:55:06 +00:00
import android.os.Build ;
2019-11-21 05:31:01 +00:00
import android.os.Handler ;
2018-07-07 00:28:58 +00:00
import android.support.annotation.NonNull ;
2019-10-10 00:38:43 +00:00
import android.support.annotation.Nullable ;
2017-01-08 17:43:43 +00:00
import android.support.multidex.MultiDexApplication ;
2017-01-11 23:37:51 +00:00
import com.google.android.gms.security.ProviderInstaller ;
2015-05-21 19:30:18 +00:00
2019-05-01 16:00:26 +00:00
import org.conscrypt.Conscrypt ;
2019-06-07 05:21:25 +00:00
import org.jetbrains.annotations.NotNull ;
2019-05-01 16:00:26 +00:00
import org.signal.aesgcmprovider.AesGcmProvider ;
2018-10-29 22:14:31 +00:00
import org.thoughtcrime.securesms.components.TypingStatusRepository ;
import org.thoughtcrime.securesms.components.TypingStatusSender ;
2019-09-24 03:33:42 +00:00
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil ;
2019-11-21 05:31:01 +00:00
import org.thoughtcrime.securesms.crypto.MasterSecretUtil ;
2019-11-28 01:49:33 +00:00
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil ;
import org.thoughtcrime.securesms.database.Address ;
2019-09-10 06:49:17 +00:00
import org.thoughtcrime.securesms.database.DatabaseContentProviders ;
2019-04-03 20:30:29 +00:00
import org.thoughtcrime.securesms.database.DatabaseFactory ;
2014-11-12 03:57:53 +00:00
import org.thoughtcrime.securesms.dependencies.AxolotlStorageModule ;
import org.thoughtcrime.securesms.dependencies.InjectableType ;
2016-12-20 17:55:52 +00:00
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule ;
2019-08-19 00:37:17 +00:00
import org.thoughtcrime.securesms.groups.GroupManager ;
2019-03-28 15:56:35 +00:00
import org.thoughtcrime.securesms.jobmanager.DependencyInjector ;
2018-06-18 19:27:04 +00:00
import org.thoughtcrime.securesms.jobmanager.JobManager ;
2019-03-28 15:56:35 +00:00
import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer ;
2016-03-12 01:07:22 +00:00
import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob ;
2019-06-18 03:23:58 +00:00
import org.thoughtcrime.securesms.jobs.FastJobStorage ;
2019-01-24 11:04:28 +00:00
import org.thoughtcrime.securesms.jobs.FcmRefreshJob ;
2019-06-18 03:23:58 +00:00
import org.thoughtcrime.securesms.jobs.JobManagerFactories ;
2018-07-07 00:28:58 +00:00
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob ;
2019-07-01 06:49:42 +00:00
import org.thoughtcrime.securesms.jobs.PushContentReceiveJob ;
2018-10-05 22:23:33 +00:00
import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob ;
2018-10-11 23:45:22 +00:00
import org.thoughtcrime.securesms.jobs.RefreshUnidentifiedDeliveryAbilityJob ;
2018-07-26 14:10:46 +00:00
import org.thoughtcrime.securesms.logging.AndroidLogger ;
import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger ;
2018-08-01 15:09:24 +00:00
import org.thoughtcrime.securesms.logging.Log ;
2018-07-26 14:10:46 +00:00
import org.thoughtcrime.securesms.logging.PersistentLogger ;
import org.thoughtcrime.securesms.logging.UncaughtExceptionLogger ;
2019-10-10 00:38:43 +00:00
import org.thoughtcrime.securesms.loki.LokiPublicChatManager ;
2019-11-21 22:35:15 +00:00
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities ;
2019-12-17 13:27:59 +00:00
import org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity ;
2020-01-31 05:18:03 +00:00
import org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundPollWorker ;
import org.thoughtcrime.securesms.loki.redesign.messaging.BackgroundPublicChatPollWorker ;
2020-02-04 23:39:35 +00:00
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiAPIDatabase ;
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiRSSFeedPoller ;
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiUserDatabase ;
2020-01-16 03:35:51 +00:00
import org.thoughtcrime.securesms.loki.redesign.utilities.Broadcaster ;
2019-04-17 14:21:30 +00:00
import org.thoughtcrime.securesms.notifications.MessageNotifier ;
2018-08-06 16:20:24 +00:00
import org.thoughtcrime.securesms.notifications.NotificationChannels ;
2020-02-24 03:57:51 +00:00
import org.thoughtcrime.securesms.profiles.AvatarHelper ;
2019-02-26 01:47:30 +00:00
import org.thoughtcrime.securesms.providers.BlobProvider ;
2016-12-30 04:54:05 +00:00
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess ;
2019-11-28 01:49:33 +00:00
import org.thoughtcrime.securesms.recipients.Recipient ;
2017-01-06 17:19:58 +00:00
import org.thoughtcrime.securesms.service.DirectoryRefreshListener ;
2016-08-16 03:23:56 +00:00
import org.thoughtcrime.securesms.service.ExpiringMessageManager ;
2018-10-15 20:27:21 +00:00
import org.thoughtcrime.securesms.service.IncomingMessageObserver ;
import org.thoughtcrime.securesms.service.KeyCachingService ;
2018-02-26 17:58:18 +00:00
import org.thoughtcrime.securesms.service.LocalBackupListener ;
2018-05-22 09:13:10 +00:00
import org.thoughtcrime.securesms.service.RotateSenderCertificateListener ;
2017-01-06 17:19:58 +00:00
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener ;
2017-02-26 22:36:43 +00:00
import org.thoughtcrime.securesms.service.UpdateApkRefreshListener ;
2014-07-25 22:14:29 +00:00
import org.thoughtcrime.securesms.util.TextSecurePreferences ;
2019-03-25 20:23:38 +00:00
import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageContextWrapper ;
2016-11-09 17:37:40 +00:00
import org.webrtc.PeerConnectionFactory ;
2017-12-22 00:37:07 +00:00
import org.webrtc.PeerConnectionFactory.InitializationOptions ;
2017-03-21 17:23:16 +00:00
import org.webrtc.voiceengine.WebRtcAudioManager ;
import org.webrtc.voiceengine.WebRtcAudioUtils ;
2016-03-23 17:34:41 +00:00
import org.whispersystems.libsignal.logging.SignalProtocolLoggerProvider ;
2019-06-25 03:51:24 +00:00
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope ;
2020-02-24 03:57:51 +00:00
import org.whispersystems.signalservice.api.util.StreamDetails ;
2019-06-25 03:51:24 +00:00
import org.whispersystems.signalservice.internal.push.SignalServiceProtos ;
2019-10-07 04:30:20 +00:00
import org.whispersystems.signalservice.loki.api.LokiAPIDatabaseProtocol ;
2020-02-12 01:26:27 +00:00
import org.whispersystems.signalservice.loki.api.LokiFileServerAPI ;
2019-10-07 04:30:20 +00:00
import org.whispersystems.signalservice.loki.api.LokiLongPoller ;
import org.whispersystems.signalservice.loki.api.LokiP2PAPI ;
import org.whispersystems.signalservice.loki.api.LokiP2PAPIDelegate ;
2019-12-02 04:03:12 +00:00
import org.whispersystems.signalservice.loki.api.LokiPublicChat ;
import org.whispersystems.signalservice.loki.api.LokiPublicChatAPI ;
2019-10-07 04:30:20 +00:00
import org.whispersystems.signalservice.loki.api.LokiRSSFeed ;
2014-07-25 22:14:29 +00:00
2020-02-24 03:57:51 +00:00
import java.io.File ;
import java.io.FileInputStream ;
import java.security.SecureRandom ;
2019-05-01 16:00:26 +00:00
import java.security.Security ;
2019-08-28 04:19:08 +00:00
import java.util.ArrayList ;
2020-02-24 03:57:51 +00:00
import java.util.Date ;
2017-03-21 17:23:16 +00:00
import java.util.HashSet ;
2019-10-10 00:38:43 +00:00
import java.util.List ;
2017-03-21 17:23:16 +00:00
import java.util.Set ;
2017-03-17 17:28:06 +00:00
import java.util.concurrent.TimeUnit ;
2014-11-12 03:57:53 +00:00
import dagger.ObjectGraph ;
2019-06-25 03:51:24 +00:00
import kotlin.Unit ;
2019-07-24 02:30:23 +00:00
import network.loki.messenger.BuildConfig ;
2014-11-12 03:57:53 +00:00
2019-09-19 05:00:52 +00:00
import static nl.komponents.kovenant.android.KovenantAndroid.startKovenant ;
import static nl.komponents.kovenant.android.KovenantAndroid.stopKovenant ;
2014-07-25 22:14:29 +00:00
/ * *
* Will be called once when the TextSecure process is created .
*
* We ' re using this as an insertion point to patch up the Android PRNG disaster ,
* to initialize the job manager , and to check for GCM registration freshness .
*
* @author Moxie Marlinspike
* /
2019-06-07 05:21:25 +00:00
public class ApplicationContext extends MultiDexApplication implements DependencyInjector , DefaultLifecycleObserver , LokiP2PAPIDelegate {
2014-07-25 22:14:29 +00:00
2018-07-26 14:10:46 +00:00
private static final String TAG = ApplicationContext . class . getSimpleName ( ) ;
2019-11-15 05:24:58 +00:00
private final static int OK_HTTP_CACHE_SIZE = 10 * 1024 * 1024 ; // 10 MB
2017-01-11 23:37:51 +00:00
2018-10-15 20:27:21 +00:00
private ExpiringMessageManager expiringMessageManager ;
2018-10-29 22:14:31 +00:00
private TypingStatusRepository typingStatusRepository ;
private TypingStatusSender typingStatusSender ;
2019-04-17 14:21:30 +00:00
private JobManager jobManager ;
2018-10-15 20:27:21 +00:00
private IncomingMessageObserver incomingMessageObserver ;
private ObjectGraph objectGraph ;
private PersistentLogger persistentLogger ;
2019-06-28 06:08:27 +00:00
// Loki
private LokiLongPoller lokiLongPoller = null ;
2019-08-28 04:19:08 +00:00
private LokiRSSFeedPoller lokiNewsFeedPoller = null ;
private LokiRSSFeedPoller lokiMessengerUpdatesFeedPoller = null ;
2019-10-10 00:38:43 +00:00
private LokiPublicChatManager lokiPublicChatManager = null ;
2019-10-15 02:39:17 +00:00
private LokiPublicChatAPI lokiPublicChatAPI = null ;
2020-01-16 03:35:51 +00:00
public Broadcaster broadcaster = null ;
2019-06-28 06:08:27 +00:00
public SignalCommunicationModule communicationModule ;
2019-06-18 02:49:21 +00:00
2018-07-07 00:28:58 +00:00
private volatile boolean isAppVisible ;
2014-07-25 22:14:29 +00:00
public static ApplicationContext getInstance ( Context context ) {
return ( ApplicationContext ) context . getApplicationContext ( ) ;
}
@Override
public void onCreate ( ) {
2018-10-04 16:09:04 +00:00
super . onCreate ( ) ;
2018-10-05 22:23:33 +00:00
Log . i ( TAG , " onCreate() " ) ;
2020-01-16 03:35:51 +00:00
broadcaster = new Broadcaster ( this ) ;
2019-11-21 05:31:01 +00:00
checkNeedsDatabaseReset ( ) ;
startKovenant ( ) ;
2019-05-01 16:00:26 +00:00
initializeSecurityProvider ( ) ;
2018-10-04 16:09:04 +00:00
initializeLogging ( ) ;
initializeCrashHandling ( ) ;
initializeDependencyInjection ( ) ;
initializeJobManager ( ) ;
2018-10-15 20:27:21 +00:00
initializeMessageRetrieval ( ) ;
2018-10-04 16:09:04 +00:00
initializeExpiringMessageManager ( ) ;
2018-10-29 22:14:31 +00:00
initializeTypingStatusRepository ( ) ;
initializeTypingStatusSender ( ) ;
2018-10-04 16:09:04 +00:00
initializeGcmCheck ( ) ;
initializeSignedPreKeyCheck ( ) ;
initializePeriodicTasks ( ) ;
initializeCircumvention ( ) ;
initializeWebRtc ( ) ;
2018-10-05 22:23:33 +00:00
initializePendingMessages ( ) ;
2018-10-11 23:45:22 +00:00
initializeUnidentifiedDeliveryAbilityRefresh ( ) ;
2019-02-26 01:47:30 +00:00
initializeBlobProvider ( ) ;
2018-10-04 16:09:04 +00:00
NotificationChannels . create ( this ) ;
ProcessLifecycleOwner . get ( ) . getLifecycle ( ) . addObserver ( this ) ;
2019-06-18 03:23:58 +00:00
// Loki - Set up P2P API if needed
setUpP2PAPI ( ) ;
2019-10-23 04:29:56 +00:00
// Loki - Update device mappings
2019-10-24 02:35:14 +00:00
if ( setUpStorageAPIIfNeeded ( ) ) {
2020-02-13 03:39:29 +00:00
String userHexEncodedPublicKey = TextSecurePreferences . getLocalNumber ( this ) ;
if ( userHexEncodedPublicKey ! = null ) {
if ( TextSecurePreferences . getNeedsIsRevokedSlaveDeviceCheck ( this ) ) {
MultiDeviceUtilities . checkIsRevokedSlaveDevice ( this ) ;
}
2019-11-21 22:35:15 +00:00
}
2019-10-23 04:29:56 +00:00
}
2020-02-24 03:57:51 +00:00
// Loki - Resubmit profile picture if needed
resubmitProfilePictureIfNeeded ( ) ;
2020-01-16 22:33:31 +00:00
// Loki - Set up public chat manager
lokiPublicChatManager = new LokiPublicChatManager ( this ) ;
2020-02-12 22:28:00 +00:00
updatePublicChatProfilePictureIfNeeded ( ) ;
2018-07-07 00:28:58 +00:00
}
@Override
public void onStart ( @NonNull LifecycleOwner owner ) {
isAppVisible = true ;
Log . i ( TAG , " App is now visible. " ) ;
executePendingContactSync ( ) ;
2018-10-15 20:27:21 +00:00
KeyCachingService . onAppForegrounded ( this ) ;
2019-06-18 03:23:58 +00:00
// Loki - Start long polling if needed
2019-07-22 00:50:35 +00:00
startLongPollingIfNeeded ( ) ;
2020-02-12 22:28:00 +00:00
// Loki - Start open group polling if needed
2019-10-15 05:06:38 +00:00
lokiPublicChatManager . startPollersIfNeeded ( ) ;
2018-07-07 00:28:58 +00:00
}
@Override
public void onStop ( @NonNull LifecycleOwner owner ) {
isAppVisible = false ;
Log . i ( TAG , " App is no longer visible. " ) ;
2018-10-15 20:27:21 +00:00
KeyCachingService . onAppBackgrounded ( this ) ;
2019-04-17 14:21:30 +00:00
MessageNotifier . setVisibleThread ( - 1 ) ;
2019-06-18 03:23:58 +00:00
// Loki - Stop long polling if needed
2019-06-19 04:47:42 +00:00
if ( lokiLongPoller ! = null ) { lokiLongPoller . stopIfNeeded ( ) ; }
2019-10-10 00:38:43 +00:00
if ( lokiPublicChatManager ! = null ) { lokiPublicChatManager . stopPollers ( ) ; }
2014-07-25 22:14:29 +00:00
}
2019-09-19 05:00:52 +00:00
@Override
public void onTerminate ( ) {
stopKovenant ( ) ;
super . onTerminate ( ) ;
}
2014-11-12 03:57:53 +00:00
@Override
public void injectDependencies ( Object object ) {
if ( object instanceof InjectableType ) {
objectGraph . inject ( object ) ;
}
}
2014-07-25 22:14:29 +00:00
public JobManager getJobManager ( ) {
return jobManager ;
}
2016-08-16 03:23:56 +00:00
public ExpiringMessageManager getExpiringMessageManager ( ) {
return expiringMessageManager ;
}
2018-10-29 22:14:31 +00:00
public TypingStatusRepository getTypingStatusRepository ( ) {
return typingStatusRepository ;
}
public TypingStatusSender getTypingStatusSender ( ) {
return typingStatusSender ;
}
2018-07-07 00:28:58 +00:00
public boolean isAppVisible ( ) {
return isAppVisible ;
}
2018-07-26 14:10:46 +00:00
public PersistentLogger getPersistentLogger ( ) {
return persistentLogger ;
}
2019-10-10 00:38:43 +00:00
public LokiPublicChatManager getLokiPublicChatManager ( ) {
return lokiPublicChatManager ;
}
2019-10-15 02:39:17 +00:00
public @Nullable LokiPublicChatAPI getLokiPublicChatAPI ( ) {
if ( lokiPublicChatAPI = = null & & IdentityKeyUtil . hasIdentityKey ( this ) ) {
2019-10-10 00:38:43 +00:00
String userHexEncodedPublicKey = TextSecurePreferences . getLocalNumber ( this ) ;
2019-12-04 02:33:05 +00:00
if ( userHexEncodedPublicKey ! = null ) {
byte [ ] userPrivateKey = IdentityKeyUtil . getIdentityKeyPair ( this ) . getPrivateKey ( ) . serialize ( ) ;
LokiAPIDatabase apiDatabase = DatabaseFactory . getLokiAPIDatabase ( this ) ;
LokiUserDatabase userDatabase = DatabaseFactory . getLokiUserDatabase ( this ) ;
lokiPublicChatAPI = new LokiPublicChatAPI ( userHexEncodedPublicKey , userPrivateKey , apiDatabase , userDatabase ) ;
}
2019-10-10 00:38:43 +00:00
}
2019-10-15 02:39:17 +00:00
return lokiPublicChatAPI ;
2019-10-10 00:38:43 +00:00
}
2019-05-01 16:00:26 +00:00
private void initializeSecurityProvider ( ) {
try {
Class . forName ( " org.signal.aesgcmprovider.AesGcmCipher " ) ;
} catch ( ClassNotFoundException e ) {
Log . e ( TAG , " Failed to find AesGcmCipher class " ) ;
throw new ProviderInitializationException ( ) ;
}
int aesPosition = Security . insertProviderAt ( new AesGcmProvider ( ) , 1 ) ;
Log . i ( TAG , " Installed AesGcmProvider: " + aesPosition ) ;
if ( aesPosition < 0 ) {
Log . e ( TAG , " Failed to install AesGcmProvider() " ) ;
throw new ProviderInitializationException ( ) ;
}
int conscryptPosition = Security . insertProviderAt ( Conscrypt . newProvider ( ) , 2 ) ;
Log . i ( TAG , " Installed Conscrypt provider: " + conscryptPosition ) ;
if ( conscryptPosition < 0 ) {
Log . w ( TAG , " Did not install Conscrypt provider. May already be present. " ) ;
}
2014-07-25 22:14:29 +00:00
}
2015-03-02 16:25:19 +00:00
private void initializeLogging ( ) {
2018-07-26 14:10:46 +00:00
persistentLogger = new PersistentLogger ( this ) ;
org . thoughtcrime . securesms . logging . Log . initialize ( new AndroidLogger ( ) , persistentLogger ) ;
SignalProtocolLoggerProvider . setProvider ( new CustomSignalProtocolLogger ( ) ) ;
}
private void initializeCrashHandling ( ) {
final Thread . UncaughtExceptionHandler originalHandler = Thread . getDefaultUncaughtExceptionHandler ( ) ;
2019-04-10 16:53:55 +00:00
Thread . setDefaultUncaughtExceptionHandler ( new UncaughtExceptionLogger ( originalHandler ) ) ;
2015-03-02 16:25:19 +00:00
}
2014-07-25 22:14:29 +00:00
private void initializeJobManager ( ) {
2019-03-28 15:56:35 +00:00
this . jobManager = new JobManager ( this , new JobManager . Configuration . Builder ( )
. setDataSerializer ( new JsonDataSerializer ( ) )
. setJobFactories ( JobManagerFactories . getJobFactories ( this ) )
. setConstraintFactories ( JobManagerFactories . getConstraintFactories ( this ) )
. setConstraintObservers ( JobManagerFactories . getConstraintObservers ( this ) )
. setJobStorage ( new FastJobStorage ( DatabaseFactory . getJobDatabase ( this ) ) )
. setDependencyInjector ( this )
. build ( ) ) ;
2014-07-25 22:14:29 +00:00
}
2018-10-15 20:27:21 +00:00
public void initializeMessageRetrieval ( ) {
this . incomingMessageObserver = new IncomingMessageObserver ( this ) ;
}
2014-11-12 03:57:53 +00:00
private void initializeDependencyInjection ( ) {
2019-06-28 06:08:27 +00:00
communicationModule = new SignalCommunicationModule ( this , new SignalServiceNetworkAccess ( this ) ) ;
this . objectGraph = ObjectGraph . create ( communicationModule , new AxolotlStorageModule ( this ) ) ;
2014-11-12 03:57:53 +00:00
}
2014-07-25 22:14:29 +00:00
private void initializeGcmCheck ( ) {
2017-03-06 19:50:51 +00:00
if ( TextSecurePreferences . isPushRegistered ( this ) ) {
2019-01-24 11:04:28 +00:00
long nextSetTime = TextSecurePreferences . getFcmTokenLastSetTime ( this ) + TimeUnit . HOURS . toMillis ( 6 ) ;
2017-03-17 17:28:06 +00:00
2019-01-24 11:04:28 +00:00
if ( TextSecurePreferences . getFcmToken ( this ) = = null | | nextSetTime < = System . currentTimeMillis ( ) ) {
2019-03-28 15:56:35 +00:00
this . jobManager . add ( new FcmRefreshJob ( ) ) ;
2017-03-17 17:28:06 +00:00
}
2014-07-25 22:14:29 +00:00
}
}
2016-03-12 01:07:22 +00:00
private void initializeSignedPreKeyCheck ( ) {
if ( ! TextSecurePreferences . isSignedPreKeyRegistered ( this ) ) {
jobManager . add ( new CreateSignedPreKeyJob ( this ) ) ;
}
}
2016-08-16 03:23:56 +00:00
private void initializeExpiringMessageManager ( ) {
this . expiringMessageManager = new ExpiringMessageManager ( this ) ;
}
2018-10-29 22:14:31 +00:00
private void initializeTypingStatusRepository ( ) {
this . typingStatusRepository = new TypingStatusRepository ( ) ;
}
private void initializeTypingStatusSender ( ) {
this . typingStatusSender = new TypingStatusSender ( this ) ;
}
2017-01-06 17:19:58 +00:00
private void initializePeriodicTasks ( ) {
RotateSignedPreKeyListener . schedule ( this ) ;
DirectoryRefreshListener . schedule ( this ) ;
2018-02-26 17:58:18 +00:00
LocalBackupListener . schedule ( this ) ;
2018-05-22 09:13:10 +00:00
RotateSenderCertificateListener . schedule ( this ) ;
2020-01-22 00:57:16 +00:00
BackgroundPollWorker . schedule ( this ) ; // Session
BackgroundPublicChatPollWorker . schedule ( this ) ; // Session
2017-02-26 22:36:43 +00:00
if ( BuildConfig . PLAY_STORE_DISABLED ) {
UpdateApkRefreshListener . schedule ( this ) ;
}
2017-01-06 17:19:58 +00:00
}
2017-03-21 17:23:16 +00:00
private void initializeWebRtc ( ) {
2017-07-21 23:29:03 +00:00
try {
Set < String > HARDWARE_AEC_BLACKLIST = new HashSet < String > ( ) { {
add ( " Pixel " ) ;
add ( " Pixel XL " ) ;
add ( " Moto G5 " ) ;
2018-04-19 17:58:39 +00:00
add ( " Moto G (5S) Plus " ) ;
2018-06-05 16:09:20 +00:00
add ( " Moto G4 " ) ;
add ( " TA-1053 " ) ;
2018-06-29 10:07:58 +00:00
add ( " Mi A1 " ) ;
2018-07-03 11:16:01 +00:00
add ( " E5823 " ) ; // Sony z5 compact
2019-02-14 05:07:34 +00:00
add ( " Redmi Note 5 " ) ;
2018-12-11 21:23:01 +00:00
add ( " FP2 " ) ; // Fairphone FP2
2019-03-10 13:29:02 +00:00
add ( " MI 5 " ) ;
2017-07-21 23:29:03 +00:00
} } ;
Set < String > OPEN_SL_ES_WHITELIST = new HashSet < String > ( ) { {
add ( " Pixel " ) ;
add ( " Pixel XL " ) ;
} } ;
2017-12-22 00:37:07 +00:00
if ( HARDWARE_AEC_BLACKLIST . contains ( Build . MODEL ) ) {
WebRtcAudioUtils . setWebRtcBasedAcousticEchoCanceler ( true ) ;
}
2017-03-21 17:23:16 +00:00
2017-12-22 00:37:07 +00:00
if ( ! OPEN_SL_ES_WHITELIST . contains ( Build . MODEL ) ) {
WebRtcAudioManager . setBlacklistDeviceForOpenSLESUsage ( true ) ;
2017-07-21 23:29:03 +00:00
}
2017-12-22 00:37:07 +00:00
2019-01-29 22:25:49 +00:00
PeerConnectionFactory . initialize ( InitializationOptions . builder ( this ) . createInitializationOptions ( ) ) ;
2017-07-21 23:29:03 +00:00
} catch ( UnsatisfiedLinkError e ) {
Log . w ( TAG , e ) ;
2017-03-21 17:23:16 +00:00
}
}
2017-12-22 00:37:07 +00:00
@SuppressLint ( " StaticFieldLeak " )
2017-01-11 23:37:51 +00:00
private void initializeCircumvention ( ) {
2017-03-21 17:23:16 +00:00
AsyncTask < Void , Void , Void > task = new AsyncTask < Void , Void , Void > ( ) {
2017-01-11 23:37:51 +00:00
@Override
protected Void doInBackground ( Void . . . params ) {
if ( new SignalServiceNetworkAccess ( ApplicationContext . this ) . isCensored ( ApplicationContext . this ) ) {
try {
ProviderInstaller . installIfNeeded ( ApplicationContext . this ) ;
} catch ( Throwable t ) {
Log . w ( TAG , t ) ;
}
}
return null ;
}
2017-03-21 17:23:16 +00:00
} ;
2017-10-23 20:03:32 +00:00
task . executeOnExecutor ( AsyncTask . THREAD_POOL_EXECUTOR ) ;
2017-01-11 23:37:51 +00:00
}
2018-07-07 00:28:58 +00:00
private void executePendingContactSync ( ) {
if ( TextSecurePreferences . needsFullContactSync ( this ) ) {
ApplicationContext . getInstance ( this ) . getJobManager ( ) . add ( new MultiDeviceContactUpdateJob ( this , true ) ) ;
}
}
2018-10-05 22:23:33 +00:00
private void initializePendingMessages ( ) {
if ( TextSecurePreferences . getNeedsMessagePull ( this ) ) {
Log . i ( TAG , " Scheduling a message fetch. " ) ;
2018-10-10 16:00:14 +00:00
ApplicationContext . getInstance ( this ) . getJobManager ( ) . add ( new PushNotificationReceiveJob ( this ) ) ;
2018-10-05 22:23:33 +00:00
TextSecurePreferences . setNeedsMessagePull ( this , false ) ;
}
}
2018-10-11 23:45:22 +00:00
private void initializeUnidentifiedDeliveryAbilityRefresh ( ) {
if ( TextSecurePreferences . isMultiDevice ( this ) & & ! TextSecurePreferences . isUnidentifiedDeliveryEnabled ( this ) ) {
2019-03-28 15:56:35 +00:00
jobManager . add ( new RefreshUnidentifiedDeliveryAbilityJob ( ) ) ;
2018-10-11 23:45:22 +00:00
}
}
2019-02-26 01:47:30 +00:00
private void initializeBlobProvider ( ) {
AsyncTask . THREAD_POOL_EXECUTOR . execute ( ( ) - > {
BlobProvider . getInstance ( ) . onSessionStart ( this ) ;
} ) ;
}
2019-03-25 20:23:38 +00:00
@Override
protected void attachBaseContext ( Context base ) {
super . attachBaseContext ( DynamicLanguageContextWrapper . updateContext ( base , TextSecurePreferences . getLanguage ( base ) ) ) ;
}
2019-05-01 16:00:26 +00:00
private static class ProviderInitializationException extends RuntimeException {
}
2019-06-07 05:21:25 +00:00
2019-06-18 03:23:58 +00:00
// region Loki
2019-10-24 02:35:14 +00:00
public boolean setUpStorageAPIIfNeeded ( ) {
2019-09-24 03:33:42 +00:00
String userHexEncodedPublicKey = TextSecurePreferences . getLocalNumber ( this ) ;
2019-09-25 04:04:25 +00:00
if ( userHexEncodedPublicKey ! = null & & IdentityKeyUtil . hasIdentityKey ( this ) ) {
2019-10-07 05:15:06 +00:00
boolean isDebugMode = BuildConfig . DEBUG ;
2019-09-25 04:04:25 +00:00
byte [ ] userPrivateKey = IdentityKeyUtil . getIdentityKeyPair ( this ) . getPrivateKey ( ) . serialize ( ) ;
LokiAPIDatabaseProtocol database = DatabaseFactory . getLokiAPIDatabase ( this ) ;
2020-02-10 22:38:05 +00:00
LokiFileServerAPI . Companion . configure ( isDebugMode , userHexEncodedPublicKey , userPrivateKey , database ) ;
2019-10-24 02:35:14 +00:00
return true ;
2019-09-25 04:04:25 +00:00
}
2019-10-24 02:35:14 +00:00
return false ;
2019-09-23 01:28:17 +00:00
}
2019-06-18 03:23:58 +00:00
public void setUpP2PAPI ( ) {
String hexEncodedPublicKey = TextSecurePreferences . getLocalNumber ( this ) ;
if ( hexEncodedPublicKey = = null ) { return ; }
LokiP2PAPI . Companion . configure ( hexEncodedPublicKey , ( isOnline , contactPublicKey ) - > {
// TODO: Implement
return null ;
} , this ) ;
}
2019-06-07 05:21:25 +00:00
@Override
public void ping ( @NotNull String s ) {
// TODO: Implement
}
2019-06-18 03:23:58 +00:00
private void setUpLongPollingIfNeeded ( ) {
if ( lokiLongPoller ! = null ) return ;
2019-07-22 00:50:35 +00:00
String userHexEncodedPublicKey = TextSecurePreferences . getLocalNumber ( this ) ;
if ( userHexEncodedPublicKey = = null ) return ;
2019-08-09 02:00:01 +00:00
LokiAPIDatabase lokiAPIDatabase = DatabaseFactory . getLokiAPIDatabase ( this ) ;
2019-06-25 03:51:24 +00:00
Context context = this ;
2020-01-16 03:35:51 +00:00
lokiLongPoller = new LokiLongPoller ( userHexEncodedPublicKey , lokiAPIDatabase , broadcaster , protos - > {
2019-08-28 04:19:08 +00:00
for ( SignalServiceProtos . Envelope proto : protos ) {
new PushContentReceiveJob ( context ) . processEnvelope ( new SignalServiceEnvelope ( proto ) ) ;
2019-06-25 03:51:24 +00:00
}
2019-08-28 04:19:08 +00:00
return Unit . INSTANCE ;
2019-06-25 03:51:24 +00:00
} ) ;
2019-06-18 03:23:58 +00:00
}
2019-08-05 02:08:23 +00:00
public void startLongPollingIfNeeded ( ) {
setUpLongPollingIfNeeded ( ) ;
if ( lokiLongPoller ! = null ) { lokiLongPoller . startIfNeeded ( ) ; }
}
2019-08-28 04:19:08 +00:00
private LokiRSSFeed lokiNewsFeed ( ) {
return new LokiRSSFeed ( " loki.network.feed " , " https://loki.network/feed/ " , " Loki News " , true ) ;
}
private LokiRSSFeed lokiMessengerUpdatesFeed ( ) {
2020-02-04 02:07:54 +00:00
return new LokiRSSFeed ( " loki.network.messenger-updates.feed " , " https://loki.network/category/messenger-updates/feed " , " Session Updates " , false ) ;
2019-08-28 04:19:08 +00:00
}
2019-10-15 05:06:38 +00:00
public void createDefaultPublicChatsIfNeeded ( ) {
List < LokiPublicChat > defaultPublicChats = LokiPublicChatAPI . Companion . getDefaultChats ( BuildConfig . DEBUG ) ;
2020-02-03 10:08:09 +00:00
for ( LokiPublicChat publicChat : defaultPublicChats ) {
long threadID = GroupManager . getPublicChatThreadId ( publicChat . getId ( ) , this ) ;
String migrationKey = publicChat . getId ( ) + " _migrated " ;
2019-10-10 00:38:43 +00:00
boolean isChatMigrated = TextSecurePreferences . getBooleanPreference ( this , migrationKey , false ) ;
2020-02-03 10:08:09 +00:00
boolean isChatSetUp = TextSecurePreferences . isChatSetUp ( this , publicChat . getId ( ) ) ;
if ( ! isChatSetUp | | ! publicChat . isDeletable ( ) ) {
lokiPublicChatManager . addChat ( publicChat . getServer ( ) , publicChat . getChannel ( ) , publicChat . getDisplayName ( ) ) ;
TextSecurePreferences . markChatSetUp ( this , publicChat . getId ( ) ) ;
2019-10-10 00:38:43 +00:00
TextSecurePreferences . setBooleanPreference ( this , migrationKey , true ) ;
} else if ( threadID > - 1 & & ! isChatMigrated ) {
2019-10-15 05:06:38 +00:00
// Migrate the old public chats
2020-02-03 10:08:09 +00:00
DatabaseFactory . getLokiThreadDatabase ( this ) . setPublicChat ( publicChat , threadID ) ;
2019-10-10 00:38:43 +00:00
TextSecurePreferences . setBooleanPreference ( this , migrationKey , true ) ;
}
2019-08-28 04:19:08 +00:00
}
}
public void createRSSFeedsIfNeeded ( ) {
ArrayList < LokiRSSFeed > feeds = new ArrayList < > ( ) ;
2020-02-12 22:28:00 +00:00
// feeds.add(lokiNewsFeed());
2019-08-28 04:19:08 +00:00
feeds . add ( lokiMessengerUpdatesFeed ( ) ) ;
for ( LokiRSSFeed feed : feeds ) {
boolean isFeedSetUp = TextSecurePreferences . isChatSetUp ( this , feed . getId ( ) ) ;
if ( ! isFeedSetUp | | ! feed . isDeletable ( ) ) {
2019-12-11 23:07:17 +00:00
GroupManager . createRSSFeedGroup ( feed . getId ( ) , this , null , feed . getDisplayName ( ) ) ;
2019-08-28 04:19:08 +00:00
TextSecurePreferences . markChatSetUp ( this , feed . getId ( ) ) ;
}
}
}
private void createRSSFeedPollersIfNeeded ( ) {
2019-09-11 23:59:15 +00:00
// Only create the RSS feed pollers if their threads aren't deleted
2019-09-10 06:49:17 +00:00
LokiRSSFeed lokiNewsFeed = lokiNewsFeed ( ) ;
2019-12-11 23:07:17 +00:00
long lokiNewsFeedThreadID = GroupManager . getRSSFeedThreadId ( lokiNewsFeed . getId ( ) , this ) ;
2019-09-11 23:59:15 +00:00
if ( lokiNewsFeedThreadID > = 0 & & lokiNewsFeedPoller = = null ) {
2019-09-10 06:49:17 +00:00
lokiNewsFeedPoller = new LokiRSSFeedPoller ( this , lokiNewsFeed ) ;
2019-09-11 23:59:15 +00:00
// Set up deletion listeners if needed
setUpThreadDeletionListeners ( lokiNewsFeedThreadID , ( ) - > {
2019-09-10 06:49:17 +00:00
if ( lokiNewsFeedPoller ! = null ) lokiNewsFeedPoller . stop ( ) ;
lokiNewsFeedPoller = null ;
} ) ;
}
2020-02-04 02:07:54 +00:00
// The user can't delete the Session Updates RSS feed
2019-09-11 23:59:15 +00:00
if ( lokiMessengerUpdatesFeedPoller = = null ) {
lokiMessengerUpdatesFeedPoller = new LokiRSSFeedPoller ( this , lokiMessengerUpdatesFeed ( ) ) ;
}
2019-09-10 06:49:17 +00:00
}
2019-09-11 23:59:15 +00:00
private void setUpThreadDeletionListeners ( long threadID , Runnable onDelete ) {
if ( threadID < 0 ) { return ; }
2019-09-10 06:49:17 +00:00
ContentObserver observer = new ContentObserver ( null ) {
2019-09-11 23:59:15 +00:00
2019-09-10 06:49:17 +00:00
@Override
public void onChange ( boolean selfChange ) {
super . onChange ( selfChange ) ;
2019-09-11 23:59:15 +00:00
// Stop the poller if thread is deleted
2019-09-10 06:49:17 +00:00
try {
2019-09-11 23:59:15 +00:00
if ( ! DatabaseFactory . getThreadDatabase ( getApplicationContext ( ) ) . hasThread ( threadID ) ) {
2019-09-10 06:49:17 +00:00
onDelete . run ( ) ;
getContentResolver ( ) . unregisterContentObserver ( this ) ;
}
} catch ( Exception e ) {
2019-09-11 23:59:15 +00:00
// TODO: Handle
2019-09-10 06:49:17 +00:00
}
}
} ;
2019-09-11 23:59:15 +00:00
this . getContentResolver ( ) . registerContentObserver ( DatabaseContentProviders . Conversation . getUriForThread ( threadID ) , true , observer ) ;
2019-08-28 04:19:08 +00:00
}
public void startRSSFeedPollersIfNeeded ( ) {
createRSSFeedPollersIfNeeded ( ) ;
2019-09-10 06:49:17 +00:00
if ( lokiNewsFeedPoller ! = null ) lokiNewsFeedPoller . startIfNeeded ( ) ;
if ( lokiMessengerUpdatesFeedPoller ! = null ) lokiMessengerUpdatesFeedPoller . startIfNeeded ( ) ;
2019-08-28 04:19:08 +00:00
}
2019-11-28 01:49:33 +00:00
2020-02-24 03:57:51 +00:00
private void resubmitProfilePictureIfNeeded ( ) {
String userHexEncodedPublicKey = TextSecurePreferences . getLocalNumber ( this ) ;
if ( userHexEncodedPublicKey = = null ) return ;
long now = new Date ( ) . getTime ( ) ;
long lastProfilePictureUpload = TextSecurePreferences . getLastProfilePictureUpload ( this ) ;
if ( now - lastProfilePictureUpload < = 14 * 24 * 60 * 60 * 1000 ) return ;
AsyncTask . execute ( ( ) - > {
String encodedProfileKey = ProfileKeyUtil . generateEncodedProfileKey ( this ) ;
byte [ ] profileKey = ProfileKeyUtil . getProfileKeyFromEncodedString ( encodedProfileKey ) ;
try {
File profilePicture = AvatarHelper . getAvatarFile ( this , Address . fromSerialized ( userHexEncodedPublicKey ) ) ;
StreamDetails stream = new StreamDetails ( new FileInputStream ( profilePicture ) , " image/jpeg " , profilePicture . length ( ) ) ;
LokiFileServerAPI . shared . uploadProfilePicture ( LokiFileServerAPI . shared . getServer ( ) , profileKey , stream , ( ) - > {
TextSecurePreferences . setLastProfilePictureUpload ( this , new Date ( ) . getTime ( ) ) ;
TextSecurePreferences . setProfileAvatarId ( this , new SecureRandom ( ) . nextInt ( ) ) ;
ProfileKeyUtil . setEncodedProfileKey ( this , encodedProfileKey ) ;
return Unit . INSTANCE ;
} ) ;
} catch ( Exception exception ) {
// Do nothing
}
} ) ;
}
2020-02-12 22:28:00 +00:00
public void updatePublicChatProfilePictureIfNeeded ( ) {
2019-11-28 01:49:33 +00:00
AsyncTask . execute ( ( ) - > {
2019-12-16 10:43:08 +00:00
LokiPublicChatAPI publicChatAPI = null ;
try {
publicChatAPI = getLokiPublicChatAPI ( ) ;
} catch ( Exception e ) {
// Do nothing
}
2019-11-28 01:49:33 +00:00
if ( publicChatAPI ! = null ) {
byte [ ] profileKey = ProfileKeyUtil . getProfileKey ( this ) ;
String url = TextSecurePreferences . getProfileAvatarUrl ( this ) ;
String ourMasterDevice = TextSecurePreferences . getMasterHexEncodedPublicKey ( this ) ;
if ( ourMasterDevice ! = null ) {
Recipient masterDevice = Recipient . from ( this , Address . fromSerialized ( ourMasterDevice ) , false ) . resolve ( ) ;
profileKey = masterDevice . getProfileKey ( ) ;
url = masterDevice . getProfileAvatar ( ) ;
}
Set < String > servers = DatabaseFactory . getLokiThreadDatabase ( this ) . getAllPublicChatServers ( ) ;
for ( String server : servers ) {
2019-12-03 04:03:13 +00:00
if ( profileKey ! = null ) {
publicChatAPI . setProfilePicture ( server , profileKey , url ) ;
}
2019-11-28 01:49:33 +00:00
}
}
} ) ;
}
2019-11-21 22:35:15 +00:00
2019-11-21 05:31:01 +00:00
public void checkNeedsDatabaseReset ( ) {
if ( TextSecurePreferences . resetDatabase ( this ) ) {
2019-11-21 22:35:15 +00:00
boolean wasUnlinked = TextSecurePreferences . databaseResetFromUnpair ( this ) ;
TextSecurePreferences . clearAll ( this ) ;
2019-11-21 23:43:22 +00:00
TextSecurePreferences . setDatabaseResetFromUnpair ( this , wasUnlinked ) ; // Loki - Re-set the preference so we can use it in the starting screen to determine whether device was unlinked or not
2019-11-21 05:31:01 +00:00
MasterSecretUtil . clear ( this ) ;
if ( this . deleteDatabase ( " signal.db " ) ) {
Log . d ( " Loki " , " Deleted database " ) ;
}
}
}
public void clearData ( ) {
TextSecurePreferences . setResetDatabase ( this , true ) ;
new Handler ( ) . postDelayed ( this : : restartApplication , 200 ) ;
}
public void restartApplication ( ) {
2019-12-17 13:27:59 +00:00
Intent intent = new Intent ( this , HomeActivity . class ) ;
2019-11-21 05:31:01 +00:00
ComponentName componentName = intent . getComponent ( ) ;
Intent mainIntent = Intent . makeRestartActivityTask ( componentName ) ;
this . startActivity ( mainIntent ) ;
Runtime . getRuntime ( ) . exit ( 0 ) ;
}
2020-02-13 03:39:29 +00:00
// endregion
2014-07-25 22:14:29 +00:00
}