From 6112ee9bd3f30035e9788855bcc53e912f2e843f Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Thu, 5 Sep 2024 15:45:48 -0400 Subject: [PATCH] Initialize AppDependencies if needed in AvatarProvider. --- app/build.gradle.kts | 1 + .../securesms/ApplicationContext.java | 8 +- .../securesms/PassphraseRequiredActivity.java | 7 +- .../securesms/apkupdate/ApkUpdateInstaller.kt | 5 +- .../ConversationListFragment.java | 4 +- .../securesms/dependencies/AppDependencies.kt | 17 +--- .../ApplicationDependencyProvider.java | 5 - .../securesms/gcm/FcmJobService.java | 3 +- .../securesms/jobs/ForegroundServiceUtil.kt | 4 +- .../securesms/jobs/MessageFetchJob.java | 4 +- .../jobs/MultiDeviceContactUpdateJob.java | 3 +- .../RoutineMessageFetchReceiver.java | 3 +- .../messages/IncomingMessageObserver.kt | 2 +- .../securesms/providers/AvatarProvider.kt | 12 +++ .../securesms/service/KeyCachingService.java | 3 +- .../CallSetupActionProcessorDelegate.java | 3 +- .../webrtc/IncomingCallActionProcessor.java | 3 +- .../IncomingGroupCallActionProcessor.java | 3 +- .../service/webrtc/SignalCallManager.java | 6 +- .../service/webrtc/WebRtcActionProcessor.java | 3 +- .../securesms/shakereport/ShakeToReport.java | 3 +- .../stories/viewer/StoryMutePolicy.kt | 3 +- .../securesms/util/AppForegroundObserver.java | 92 ------------------ .../securesms/util/AppForegroundObserver.kt | 96 +++++++++++++++++++ .../video/exo/SimpleExoPlayerPool.kt | 2 +- .../MockApplicationDependencyProvider.kt | 5 - 26 files changed, 154 insertions(+), 146 deletions(-) delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/util/AppForegroundObserver.java create mode 100644 app/src/main/java/org/thoughtcrime/securesms/util/AppForegroundObserver.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7da4136176..b689d472d3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -91,6 +91,7 @@ android { kotlinOptions { jvmTarget = signalKotlinJvmTarget + freeCompilerArgs = listOf("-Xjvm-default=all") } keystores["debug"]?.let { properties -> diff --git a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java index dba002e80f..ed8b5e33d0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java @@ -167,7 +167,7 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr .addBlocking("scrubber", () -> Scrubber.setIdentifierHmacKeyProvider(() -> SignalStore.svr().getOrCreateMasterKey().deriveLoggingKey())) .addBlocking("first-launch", this::initializeFirstEverAppLaunch) .addBlocking("app-migrations", this::initializeApplicationMigrations) - .addBlocking("lifecycle-observer", () -> AppDependencies.getAppForegroundObserver().addListener(this)) + .addBlocking("lifecycle-observer", () -> AppForegroundObserver.addListener(this)) .addBlocking("message-retriever", this::initializeMessageRetrieval) .addBlocking("dynamic-theme", () -> DynamicTheme.setDefaultDayNightMode(this)) .addBlocking("proxy-init", () -> { @@ -366,7 +366,11 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr @VisibleForTesting void initializeAppDependencies() { - AppDependencies.init(this, new ApplicationDependencyProvider(this)); + if (!AppDependencies.isInitialized()) { + Log.i(TAG, "Initializing AppDependencies."); + AppDependencies.init(this, new ApplicationDependencyProvider(this)); + } + AppForegroundObserver.begin(); } private void initializeFirstEverAppLaunch() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/PassphraseRequiredActivity.java b/app/src/main/java/org/thoughtcrime/securesms/PassphraseRequiredActivity.java index 1b36a37742..a9fb3b8c49 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/PassphraseRequiredActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/PassphraseRequiredActivity.java @@ -31,6 +31,7 @@ import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.registration.ui.RegistrationActivity; import org.thoughtcrime.securesms.restore.RestoreActivity; import org.thoughtcrime.securesms.service.KeyCachingService; +import org.thoughtcrime.securesms.util.AppForegroundObserver; import org.thoughtcrime.securesms.util.AppStartup; import org.thoughtcrime.securesms.util.RemoteConfig; import org.thoughtcrime.securesms.util.TextSecurePreferences; @@ -92,8 +93,8 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements @Override public void onMasterSecretCleared() { Log.d(TAG, "onMasterSecretCleared()"); - if (AppDependencies.getAppForegroundObserver().isForegrounded()) routeApplicationState(true); - else finish(); + if (AppForegroundObserver.isForegrounded()) routeApplicationState(true); + else finish(); } protected T initFragment(@IdRes int target, @@ -209,7 +210,7 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements private Intent getPromptPassphraseIntent() { Intent intent = getRoutedIntent(PassphrasePromptActivity.class, getIntent()); - intent.putExtra(PassphrasePromptActivity.FROM_FOREGROUND, AppDependencies.getAppForegroundObserver().isForegrounded()); + intent.putExtra(PassphrasePromptActivity.FROM_FOREGROUND, AppForegroundObserver.isForegrounded()); return intent; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/apkupdate/ApkUpdateInstaller.kt b/app/src/main/java/org/thoughtcrime/securesms/apkupdate/ApkUpdateInstaller.kt index 39434cdda4..96a8f2bce9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/apkupdate/ApkUpdateInstaller.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/apkupdate/ApkUpdateInstaller.kt @@ -17,6 +17,7 @@ import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.dependencies.AppDependencies import org.thoughtcrime.securesms.jobs.ApkUpdateJob import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.util.AppForegroundObserver import org.thoughtcrime.securesms.util.Environment import org.thoughtcrime.securesms.util.FileUtils import java.io.FileInputStream @@ -61,7 +62,7 @@ object ApkUpdateInstaller { } if (!userInitiated && !shouldAutoUpdate()) { - Log.w(TAG, "Not user-initiated and not eligible for auto-update. Prompting. (API=${Build.VERSION.SDK_INT}, Foreground=${AppDependencies.appForegroundObserver.isForegrounded}, AutoUpdate=${SignalStore.apkUpdate.autoUpdate})") + Log.w(TAG, "Not user-initiated and not eligible for auto-update. Prompting. (API=${Build.VERSION.SDK_INT}, Foreground=${AppForegroundObserver.isForegrounded()}, AutoUpdate=${SignalStore.apkUpdate.autoUpdate})") ApkUpdateNotifications.showInstallPrompt(context, downloadId) return } @@ -145,6 +146,6 @@ object ApkUpdateInstaller { private fun shouldAutoUpdate(): Boolean { // TODO Auto-updates temporarily restricted to nightlies. Once we have designs for allowing users to opt-out of auto-updates, we can re-enable this - return Environment.IS_NIGHTLY && Build.VERSION.SDK_INT >= 31 && SignalStore.apkUpdate.autoUpdate && !AppDependencies.appForegroundObserver.isForegrounded + return Environment.IS_NIGHTLY && Build.VERSION.SDK_INT >= 31 && SignalStore.apkUpdate.autoUpdate && !AppForegroundObserver.isForegrounded() } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java index 4ce7392de3..017663431e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListFragment.java @@ -529,7 +529,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode @Override public void onStart() { super.onStart(); - AppDependencies.getAppForegroundObserver().addListener(appForegroundObserver); + AppForegroundObserver.addListener(appForegroundObserver); itemAnimator.disable(); } @@ -546,7 +546,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode @Override public void onStop() { super.onStop(); - AppDependencies.getAppForegroundObserver().removeListener(appForegroundObserver); + AppForegroundObserver.removeListener(appForegroundObserver); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/AppDependencies.kt b/app/src/main/java/org/thoughtcrime/securesms/dependencies/AppDependencies.kt index ab923317d1..44f7541e00 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/AppDependencies.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/AppDependencies.kt @@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.dependencies import android.annotation.SuppressLint import android.app.Application -import androidx.annotation.MainThread import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.subjects.BehaviorSubject import io.reactivex.rxjava3.subjects.Subject @@ -35,7 +34,6 @@ import org.thoughtcrime.securesms.service.ScheduledMessageManager import org.thoughtcrime.securesms.service.TrimThreadsByDateManager import org.thoughtcrime.securesms.service.webrtc.SignalCallManager import org.thoughtcrime.securesms.shakereport.ShakeToReport -import org.thoughtcrime.securesms.util.AppForegroundObserver import org.thoughtcrime.securesms.util.EarlyMessageCache import org.thoughtcrime.securesms.util.FrameRateTracker import org.thoughtcrime.securesms.video.exo.GiphyMp4Cache @@ -69,21 +67,15 @@ object AppDependencies { private lateinit var _application: Application private lateinit var provider: Provider - // Needs special initialization because it needs to be created on the main thread - private lateinit var _appForegroundObserver: AppForegroundObserver - @JvmStatic - @MainThread + @Synchronized fun init(application: Application, provider: Provider) { if (this::_application.isInitialized || this::provider.isInitialized) { - throw IllegalStateException("Already initialized!") + return } _application = application AppDependencies.provider = provider - - _appForegroundObserver = provider.provideAppForegroundObserver() - _appForegroundObserver.begin() } @JvmStatic @@ -94,10 +86,6 @@ object AppDependencies { val application: Application get() = _application - @JvmStatic - val appForegroundObserver: AppForegroundObserver - get() = _appForegroundObserver - @JvmStatic val recipientCache: LiveRecipientCache by lazy { provider.provideRecipientCache() @@ -339,7 +327,6 @@ object AppDependencies { fun provideDatabaseObserver(): DatabaseObserver fun providePayments(signalServiceAccountManager: SignalServiceAccountManager): Payments fun provideShakeToReport(): ShakeToReport - fun provideAppForegroundObserver(): AppForegroundObserver fun provideSignalCallManager(): SignalCallManager fun providePendingRetryReceiptManager(): PendingRetryReceiptManager fun providePendingRetryReceiptCache(): PendingRetryReceiptCache diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java index ffc691c6c9..8077bad4ce 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java @@ -275,11 +275,6 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider { return new ShakeToReport(context); } - @Override - public @NonNull AppForegroundObserver provideAppForegroundObserver() { - return new AppForegroundObserver(); - } - @Override public @NonNull SignalCallManager provideSignalCallManager() { return new SignalCallManager(context); diff --git a/app/src/main/java/org/thoughtcrime/securesms/gcm/FcmJobService.java b/app/src/main/java/org/thoughtcrime/securesms/gcm/FcmJobService.java index f7cd3093c2..8e62df2a1c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/gcm/FcmJobService.java +++ b/app/src/main/java/org/thoughtcrime/securesms/gcm/FcmJobService.java @@ -13,6 +13,7 @@ import org.signal.core.util.concurrent.SignalExecutors; import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.dependencies.AppDependencies; import org.thoughtcrime.securesms.messages.WebSocketDrainer; +import org.thoughtcrime.securesms.util.AppForegroundObserver; import org.thoughtcrime.securesms.util.ServiceUtil; /** @@ -39,7 +40,7 @@ public class FcmJobService extends JobService { public boolean onStartJob(JobParameters params) { Log.d(TAG, "onStartJob()"); - if (AppDependencies.getAppForegroundObserver().isForegrounded()) { + if (AppForegroundObserver.isForegrounded()) { Log.i(TAG, "App is foregrounded. No need to run."); return false; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/ForegroundServiceUtil.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/ForegroundServiceUtil.kt index 9db7227a7c..1a5f7a5007 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/ForegroundServiceUtil.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/ForegroundServiceUtil.kt @@ -12,9 +12,9 @@ import androidx.annotation.WorkerThread import androidx.core.content.ContextCompat import org.signal.core.util.PendingIntentFlags import org.signal.core.util.logging.Log -import org.thoughtcrime.securesms.dependencies.AppDependencies import org.thoughtcrime.securesms.service.GenericForegroundService import org.thoughtcrime.securesms.service.NotificationController +import org.thoughtcrime.securesms.util.AppForegroundObserver import org.thoughtcrime.securesms.util.ServiceUtil import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit @@ -137,7 +137,7 @@ object ForegroundServiceUtil { private fun blockUntilCapable(context: Context, timeout: Long = DEFAULT_TIMEOUT): Boolean { val alarmManager = ServiceUtil.getAlarmManager(context) - if (Build.VERSION.SDK_INT < 31 || AppDependencies.appForegroundObserver.isForegrounded) { + if (Build.VERSION.SDK_INT < 31 || AppForegroundObserver.isForegrounded()) { return true } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/MessageFetchJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/MessageFetchJob.java index 7b9de2bfdf..a9257c5f07 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/MessageFetchJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/MessageFetchJob.java @@ -125,7 +125,7 @@ public final class MessageFetchJob extends BaseJob { @Override public void close() { - AppDependencies.getAppForegroundObserver().removeListener(this); + AppForegroundObserver.removeListener(this); closeNotificationController(); } @@ -157,7 +157,7 @@ public final class MessageFetchJob extends BaseJob { static ForegroundServiceController create(@NonNull Context context) { ForegroundServiceController instance = new ForegroundServiceController(context); - AppDependencies.getAppForegroundObserver().addListener(instance); + AppForegroundObserver.addListener(instance); return instance; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java index 0c5797978f..7300754a3d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java @@ -29,6 +29,7 @@ import org.thoughtcrime.securesms.providers.BlobProvider; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientUtil; +import org.thoughtcrime.securesms.util.AppForegroundObserver; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; @@ -196,7 +197,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob { private void generateFullContactUpdate() throws IOException, UntrustedIdentityException, NetworkException { - boolean isAppVisible = AppDependencies.getAppForegroundObserver().isForegrounded(); + boolean isAppVisible = AppForegroundObserver.isForegrounded(); long timeSinceLastSync = System.currentTimeMillis() - TextSecurePreferences.getLastFullContactSyncTime(context); Log.d(TAG, "Requesting a full contact sync. forced = " + forceSync + ", appVisible = " + isAppVisible + ", timeSinceLastSync = " + timeSinceLastSync + " ms"); diff --git a/app/src/main/java/org/thoughtcrime/securesms/messageprocessingalarm/RoutineMessageFetchReceiver.java b/app/src/main/java/org/thoughtcrime/securesms/messageprocessingalarm/RoutineMessageFetchReceiver.java index dcec1665a4..0da78c94ab 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messageprocessingalarm/RoutineMessageFetchReceiver.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messageprocessingalarm/RoutineMessageFetchReceiver.java @@ -18,6 +18,7 @@ import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.dependencies.AppDependencies; import org.thoughtcrime.securesms.jobmanager.JobTracker; import org.thoughtcrime.securesms.jobs.MessageFetchJob; +import org.thoughtcrime.securesms.util.AppForegroundObserver; import org.thoughtcrime.securesms.util.RemoteConfig; import java.util.Locale; @@ -43,7 +44,7 @@ public final class RoutineMessageFetchReceiver extends BroadcastReceiver { startOrUpdateAlarm(context); } else if (BROADCAST_ACTION.equals(intent.getAction())) { - if (AppDependencies.getAppForegroundObserver().isForegrounded()) { + if (AppForegroundObserver.isForegrounded()) { Log.i(TAG, "App is foregrounded"); return; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.kt index 96af0606d6..6ee92aa296 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.kt @@ -130,7 +130,7 @@ class IncomingMessageObserver(private val context: Application) { } } - AppDependencies.appForegroundObserver.addListener(object : AppForegroundObserver.Listener { + AppForegroundObserver.addListener(object : AppForegroundObserver.Listener { override fun onForeground() { onAppForegrounded() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/providers/AvatarProvider.kt b/app/src/main/java/org/thoughtcrime/securesms/providers/AvatarProvider.kt index d218c61a99..e95bf8e551 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/providers/AvatarProvider.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/providers/AvatarProvider.kt @@ -15,6 +15,7 @@ import android.graphics.Bitmap import android.net.Uri import android.os.ParcelFileDescriptor import org.signal.core.util.concurrent.SignalExecutors +import org.signal.core.util.logging.AndroidLogger import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.BuildConfig @@ -22,7 +23,10 @@ import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider import org.thoughtcrime.securesms.crypto.DatabaseSecretProvider import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.database.SqlCipherLibraryLoader +import org.thoughtcrime.securesms.dependencies.AppDependencies +import org.thoughtcrime.securesms.dependencies.ApplicationDependencyProvider import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.logging.PersistentLogger import org.thoughtcrime.securesms.profiles.AvatarHelper import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientCreator @@ -31,6 +35,7 @@ import org.thoughtcrime.securesms.service.KeyCachingService import org.thoughtcrime.securesms.util.AdaptiveBitmapMetrics import org.thoughtcrime.securesms.util.AvatarUtil import org.thoughtcrime.securesms.util.MediaUtil +import org.thoughtcrime.securesms.util.RemoteConfig import java.io.File import java.io.FileNotFoundException import java.io.IOException @@ -73,6 +78,13 @@ class AvatarProvider : BaseContentProvider() { SignalStore.init(application) + Log.initialize(RemoteConfig::internalUser, AndroidLogger(), PersistentLogger(application)) + + if (!AppDependencies.isInitialized) { + Log.i(TAG, "Initializing AppDependencies.") + AppDependencies.init(application, ApplicationDependencyProvider(application)) + } + return application } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/KeyCachingService.java b/app/src/main/java/org/thoughtcrime/securesms/service/KeyCachingService.java index 8ae4fde452..bd5dce7add 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/KeyCachingService.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/KeyCachingService.java @@ -46,6 +46,7 @@ import org.thoughtcrime.securesms.dependencies.AppDependencies; import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.migrations.ApplicationMigrations; import org.thoughtcrime.securesms.notifications.NotificationChannels; +import org.thoughtcrime.securesms.util.AppForegroundObserver; import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.ServiceUtil; @@ -229,7 +230,7 @@ public class KeyCachingService extends Service { } private static void startTimeoutIfAppropriate(@NonNull Context context) { - boolean appVisible = AppDependencies.getAppForegroundObserver().isForegrounded(); + boolean appVisible = AppForegroundObserver.isForegrounded(); boolean secretSet = KeyCachingService.masterSecret != null; boolean timeoutEnabled = SignalStore.settings().getPassphraseTimeoutEnabled(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/CallSetupActionProcessorDelegate.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/CallSetupActionProcessorDelegate.java index aee189372e..dcfb79df75 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/CallSetupActionProcessorDelegate.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/CallSetupActionProcessorDelegate.java @@ -10,6 +10,7 @@ import org.thoughtcrime.securesms.events.WebRtcViewModel; import org.thoughtcrime.securesms.ringrtc.Camera; import org.thoughtcrime.securesms.ringrtc.RemotePeer; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState; +import org.thoughtcrime.securesms.util.AppForegroundObserver; import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager; import org.thoughtcrime.securesms.webrtc.locks.LockManager; @@ -43,7 +44,7 @@ public class CallSetupActionProcessorDelegate extends WebRtcActionProcessor { currentState.getCallSetupState(activePeer).isAcceptWithVideo() || currentState.getLocalDeviceState().getCameraState().isEnabled() ); - AppDependencies.getAppForegroundObserver().removeListener(webRtcInteractor.getForegroundListener()); + AppForegroundObserver.removeListener(webRtcInteractor.getForegroundListener()); webRtcInteractor.startAudioCommunication(); webRtcInteractor.activateCall(activePeer.getId()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingCallActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingCallActionProcessor.java index 04ba54ec8c..7ab9100ea6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingCallActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingCallActionProcessor.java @@ -25,6 +25,7 @@ import org.thoughtcrime.securesms.ringrtc.RemotePeer; import org.thoughtcrime.securesms.service.webrtc.state.CallSetupState; import org.thoughtcrime.securesms.service.webrtc.state.VideoState; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState; +import org.thoughtcrime.securesms.util.AppForegroundObserver; import org.thoughtcrime.securesms.util.NetworkUtil; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.webrtc.locks.LockManager; @@ -191,7 +192,7 @@ public class IncomingCallActionProcessor extends DeviceAwareActionProcessor { boolean started = webRtcInteractor.startWebRtcCallActivityIfPossible(); if (!started) { Log.i(TAG, "Unable to start call activity due to OS version or not being in the foreground"); - AppDependencies.getAppForegroundObserver().addListener(webRtcInteractor.getForegroundListener()); + AppForegroundObserver.addListener(webRtcInteractor.getForegroundListener()); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingGroupCallActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingGroupCallActionProcessor.java index a9fd1d6996..f8f6bf4404 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingGroupCallActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingGroupCallActionProcessor.java @@ -23,6 +23,7 @@ import org.thoughtcrime.securesms.notifications.DoNotDisturbUtil; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.ringrtc.RemotePeer; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState; +import org.thoughtcrime.securesms.util.AppForegroundObserver; import org.thoughtcrime.securesms.util.NetworkUtil; import org.thoughtcrime.securesms.webrtc.locks.LockManager; import org.whispersystems.signalservice.api.push.ServiceId.ACI; @@ -128,7 +129,7 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro boolean started = webRtcInteractor.startWebRtcCallActivityIfPossible(); if (!started) { Log.i(TAG, "Unable to start call activity due to OS version or not being in the foreground"); - AppDependencies.getAppForegroundObserver().addListener(webRtcInteractor.getForegroundListener()); + AppForegroundObserver.addListener(webRtcInteractor.getForegroundListener()); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java index 6cd7e1067e..fad7d53457 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java @@ -991,7 +991,7 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall. Log.i(TAG, "Starting call activity from foreground listener"); startCallCardActivityIfPossible(); } - AppDependencies.getAppForegroundObserver().removeListener(this); + AppForegroundObserver.removeListener(this); return s; }); } @@ -1218,7 +1218,7 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall. } public void relaunchPipOnForeground() { - AppDependencies.getAppForegroundObserver().addListener(new RelaunchListener(AppDependencies.getAppForegroundObserver().isForegrounded())); + AppForegroundObserver.addListener(new RelaunchListener(AppForegroundObserver.isForegrounded())); } private void processSendMessageFailureWithChangeDetection(@NonNull RemotePeer remotePeer, @@ -1265,7 +1265,7 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall. return s; }); } - AppDependencies.getAppForegroundObserver().removeListener(this); + AppForegroundObserver.removeListener(this); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java index fbc79693a3..39308e9907 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java @@ -44,6 +44,7 @@ import org.thoughtcrime.securesms.service.webrtc.WebRtcData.ReceivedOfferMetadat import org.thoughtcrime.securesms.service.webrtc.state.WebRtcEphemeralState; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceStateBuilder; +import org.thoughtcrime.securesms.util.AppForegroundObserver; import org.thoughtcrime.securesms.util.NetworkUtil; import org.thoughtcrime.securesms.util.TelephonyUtil; import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager; @@ -692,7 +693,7 @@ public abstract class WebRtcActionProcessor { activePeer = remotePeer; } - AppDependencies.getAppForegroundObserver().removeListener(webRtcInteractor.getForegroundListener()); + AppForegroundObserver.removeListener(webRtcInteractor.getForegroundListener()); if (activePeer.getState() != CallState.IDLE) { webRtcInteractor.updatePhoneState(LockManager.PhoneState.PROCESSING); diff --git a/app/src/main/java/org/thoughtcrime/securesms/shakereport/ShakeToReport.java b/app/src/main/java/org/thoughtcrime/securesms/shakereport/ShakeToReport.java index 78af07893c..3f04ef58f0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/shakereport/ShakeToReport.java +++ b/app/src/main/java/org/thoughtcrime/securesms/shakereport/ShakeToReport.java @@ -21,6 +21,7 @@ import org.thoughtcrime.securesms.dependencies.AppDependencies; import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.logsubmit.SubmitDebugLogRepository; import org.thoughtcrime.securesms.sharing.MultiShareArgs; +import org.thoughtcrime.securesms.util.AppForegroundObserver; import org.thoughtcrime.securesms.util.ServiceUtil; import org.thoughtcrime.securesms.util.views.SimpleProgressDialog; @@ -142,7 +143,7 @@ public final class ShakeToReport implements ShakeDetector.Listener { } private void enableIfVisible() { - if (AppDependencies.getAppForegroundObserver().isForegrounded()) { + if (AppForegroundObserver.isForegrounded()) { enable(); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/StoryMutePolicy.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/StoryMutePolicy.kt index ada2c70654..632ca34345 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/StoryMutePolicy.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/StoryMutePolicy.kt @@ -1,6 +1,5 @@ package org.thoughtcrime.securesms.stories.viewer -import org.thoughtcrime.securesms.dependencies.AppDependencies import org.thoughtcrime.securesms.util.AppForegroundObserver /** @@ -11,7 +10,7 @@ object StoryMutePolicy : AppForegroundObserver.Listener { var isContentMuted: Boolean = true fun initialize() { - AppDependencies.appForegroundObserver.addListener(this) + AppForegroundObserver.addListener(this) } override fun onBackground() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/AppForegroundObserver.java b/app/src/main/java/org/thoughtcrime/securesms/util/AppForegroundObserver.java deleted file mode 100644 index d32812816b..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/util/AppForegroundObserver.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.thoughtcrime.securesms.util; - -import androidx.annotation.AnyThread; -import androidx.annotation.MainThread; -import androidx.annotation.NonNull; -import androidx.lifecycle.DefaultLifecycleObserver; -import androidx.lifecycle.LifecycleOwner; -import androidx.lifecycle.ProcessLifecycleOwner; - -import org.signal.core.util.ThreadUtil; - -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; - -/** - * A wrapper around {@link ProcessLifecycleOwner} that allows for safely adding/removing observers - * on multiple threads. - */ -public class AppForegroundObserver { - - private final Set listeners = new CopyOnWriteArraySet<>(); - - private volatile Boolean isForegrounded = null; - - @MainThread - public void begin() { - ThreadUtil.assertMainThread(); - - ProcessLifecycleOwner.get().getLifecycle().addObserver(new DefaultLifecycleObserver() { - @Override - public void onStart(@NonNull LifecycleOwner owner) { - onForeground(); - } - - @Override - public void onStop(@NonNull LifecycleOwner owner) { - onBackground(); - } - }); - } - - /** - * Adds a listener to be notified of when the app moves between the background and the foreground. - * To mimic the behavior of subscribing to {@link ProcessLifecycleOwner}, this listener will be - * immediately notified of the foreground state if we've experienced a foreground/background event - * already. - */ - @AnyThread - public void addListener(@NonNull Listener listener) { - listeners.add(listener); - - if (isForegrounded != null) { - if (isForegrounded) { - listener.onForeground(); - } else { - listener.onBackground(); - } - } - } - - @AnyThread - public void removeListener(@NonNull Listener listener) { - listeners.remove(listener); - } - - public boolean isForegrounded() { - return isForegrounded != null && isForegrounded; - } - - @MainThread - private void onForeground() { - isForegrounded = true; - - for (Listener listener : listeners) { - listener.onForeground(); - } - } - - @MainThread - private void onBackground() { - isForegrounded = false; - - for (Listener listener : listeners) { - listener.onBackground(); - } - } - - public interface Listener { - default void onForeground() {} - default void onBackground() {} - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/AppForegroundObserver.kt b/app/src/main/java/org/thoughtcrime/securesms/util/AppForegroundObserver.kt new file mode 100644 index 0000000000..219c2e4e73 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/util/AppForegroundObserver.kt @@ -0,0 +1,96 @@ +package org.thoughtcrime.securesms.util + +import androidx.annotation.AnyThread +import androidx.annotation.MainThread +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.ProcessLifecycleOwner +import org.signal.core.util.ThreadUtil +import java.util.concurrent.CopyOnWriteArraySet +import kotlin.concurrent.Volatile + +/** + * A wrapper around [ProcessLifecycleOwner] that allows for safely adding/removing observers + * on multiple threads. + */ +object AppForegroundObserver { + private val listeners: MutableSet = CopyOnWriteArraySet() + + @Volatile + private var isInitialized: Boolean = false + + @Volatile + private var isForegrounded: Boolean = false + + @MainThread + @JvmStatic + fun begin() { + ThreadUtil.assertMainThread() + + ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver { + override fun onStart(owner: LifecycleOwner) { + onForeground() + } + + override fun onStop(owner: LifecycleOwner) { + onBackground() + } + }) + + isInitialized = true + } + + /** + * Adds a listener to be notified of when the app moves between the background and the foreground. + * To mimic the behavior of subscribing to [ProcessLifecycleOwner], this listener will be + * immediately notified of the foreground state if we've experienced a foreground/background event + * already. + */ + @AnyThread + @JvmStatic + fun addListener(listener: Listener) { + listeners.add(listener) + + if (isInitialized) { + if (isForegrounded) { + listener.onForeground() + } else { + listener.onBackground() + } + } + } + + @AnyThread + @JvmStatic + fun removeListener(listener: Listener) { + listeners.remove(listener) + } + + @JvmStatic + fun isForegrounded(): Boolean { + return isInitialized && isForegrounded + } + + @MainThread + private fun onForeground() { + isForegrounded = true + + for (listener in listeners) { + listener.onForeground() + } + } + + @MainThread + private fun onBackground() { + isForegrounded = false + + for (listener in listeners) { + listener.onBackground() + } + } + + interface Listener { + fun onForeground() {} + fun onBackground() {} + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/video/exo/SimpleExoPlayerPool.kt b/app/src/main/java/org/thoughtcrime/securesms/video/exo/SimpleExoPlayerPool.kt index 189b0fe414..a282243db4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/video/exo/SimpleExoPlayerPool.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/video/exo/SimpleExoPlayerPool.kt @@ -30,7 +30,7 @@ class SimpleExoPlayerPool(context: Context) : ExoPlayerPool(MAXIMUM_R private val mediaSourceFactory: MediaSource.Factory = DefaultMediaSourceFactory(dataSourceFactory) init { - AppDependencies.appForegroundObserver.addListener(this) + AppForegroundObserver.addListener(this) } /** diff --git a/app/src/test/java/org/thoughtcrime/securesms/dependencies/MockApplicationDependencyProvider.kt b/app/src/test/java/org/thoughtcrime/securesms/dependencies/MockApplicationDependencyProvider.kt index 6f5a320610..f91aa05f80 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/dependencies/MockApplicationDependencyProvider.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/dependencies/MockApplicationDependencyProvider.kt @@ -28,7 +28,6 @@ import org.thoughtcrime.securesms.service.ScheduledMessageManager import org.thoughtcrime.securesms.service.TrimThreadsByDateManager import org.thoughtcrime.securesms.service.webrtc.SignalCallManager import org.thoughtcrime.securesms.shakereport.ShakeToReport -import org.thoughtcrime.securesms.util.AppForegroundObserver import org.thoughtcrime.securesms.util.EarlyMessageCache import org.thoughtcrime.securesms.util.FrameRateTracker import org.thoughtcrime.securesms.video.exo.GiphyMp4Cache @@ -141,10 +140,6 @@ class MockApplicationDependencyProvider : AppDependencies.Provider { return mockk() } - override fun provideAppForegroundObserver(): AppForegroundObserver { - return Mockito.mock(AppForegroundObserver::class.java) - } - override fun provideSignalCallManager(): SignalCallManager { return mockk() }