diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/BriarDesktopApp.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/BriarDesktopApp.kt
index 252c2b6080d0b3ad884ec8640dba4dbbc1f13f8f..0070390de2b0967f75ff8b0f563762d3e81f50d4 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/BriarDesktopApp.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/BriarDesktopApp.kt
@@ -24,20 +24,19 @@ import org.briarproject.bramble.BrambleCoreModule
 import org.briarproject.briar.BriarCoreEagerSingletons
 import org.briarproject.briar.BriarCoreModule
 import org.briarproject.briar.desktop.ui.BriarUi
-import java.security.SecureRandom
 import javax.inject.Singleton
 
+// corresponding Briar Android class in
+// briar/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java
 @Component(
     modules = [
         BrambleCoreModule::class,
         BriarCoreModule::class,
-        DesktopModule::class
+        DesktopModule::class,
     ]
 )
 @Singleton
 internal interface BriarDesktopApp : BrambleCoreEagerSingletons, BriarCoreEagerSingletons {
 
     fun getBriarUi(): BriarUi
-
-    fun getSecureRandom(): SecureRandom
 }
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/DesktopCoreModule.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/DesktopCoreModule.kt
new file mode 100644
index 0000000000000000000000000000000000000000..6b5e42f68e5d58828a42da06b08851e21dc2700b
--- /dev/null
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/DesktopCoreModule.kt
@@ -0,0 +1,197 @@
+/*
+ * Briar Desktop
+ * Copyright (C) 2021-2022 The Briar Project
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package org.briarproject.briar.desktop
+
+import dagger.Module
+import dagger.Provides
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.asExecutor
+import kotlinx.coroutines.swing.Swing
+import org.briarproject.bramble.account.AccountModule
+import org.briarproject.bramble.api.db.DatabaseConfig
+import org.briarproject.bramble.api.event.EventExecutor
+import org.briarproject.bramble.api.plugin.PluginConfig
+import org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_CONTROL_PORT
+import org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_SOCKS_PORT
+import org.briarproject.bramble.api.plugin.TorControlPort
+import org.briarproject.bramble.api.plugin.TorDirectory
+import org.briarproject.bramble.api.plugin.TorSocksPort
+import org.briarproject.bramble.api.plugin.TransportId
+import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory
+import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory
+import org.briarproject.bramble.battery.DefaultBatteryManagerModule
+import org.briarproject.bramble.network.JavaNetworkModule
+import org.briarproject.bramble.plugin.tcp.LanTcpPluginFactory
+import org.briarproject.bramble.plugin.tor.CircumventionModule
+import org.briarproject.bramble.plugin.tor.UnixTorPluginFactory
+import org.briarproject.bramble.socks.SocksModule
+import org.briarproject.bramble.system.ClockModule
+import org.briarproject.bramble.system.DefaultTaskSchedulerModule
+import org.briarproject.bramble.system.DefaultWakefulIoExecutorModule
+import org.briarproject.bramble.system.DesktopSecureRandomModule
+import org.briarproject.bramble.system.JavaSystemModule
+import org.briarproject.bramble.util.OsUtils.isLinux
+import org.briarproject.bramble.util.OsUtils.isMac
+import org.briarproject.briar.attachment.AttachmentModule
+import org.briarproject.briar.desktop.attachment.media.ImageCompressor
+import org.briarproject.briar.desktop.attachment.media.ImageCompressorImpl
+import org.briarproject.briar.desktop.notification.SoundNotificationProvider
+import org.briarproject.briar.desktop.notification.StubNotificationProvider
+import org.briarproject.briar.desktop.notification.VisualNotificationProvider
+import org.briarproject.briar.desktop.notification.linux.LibnotifyNotificationProvider
+import org.briarproject.briar.desktop.settings.Configuration
+import org.briarproject.briar.desktop.settings.ConfigurationImpl
+import org.briarproject.briar.desktop.settings.EncryptedSettings
+import org.briarproject.briar.desktop.settings.EncryptedSettingsImpl
+import org.briarproject.briar.desktop.settings.EncryptedSettingsReadOnly
+import org.briarproject.briar.desktop.settings.UnencryptedSettings
+import org.briarproject.briar.desktop.settings.UnencryptedSettingsImpl
+import org.briarproject.briar.desktop.settings.UnencryptedSettingsReadOnly
+import org.briarproject.briar.desktop.threading.BriarExecutors
+import org.briarproject.briar.desktop.threading.BriarExecutorsImpl
+import org.briarproject.briar.desktop.threading.UiExecutor
+import org.briarproject.briar.desktop.ui.BriarUi
+import org.briarproject.briar.desktop.ui.BriarUiImpl
+import org.briarproject.briar.desktop.ui.MessageCounter
+import org.briarproject.briar.desktop.ui.MessageCounterImpl
+import org.briarproject.briar.desktop.viewmodel.ViewModelModule
+import org.briarproject.briar.identity.IdentityModule
+import java.io.File
+import java.nio.file.Path
+import java.util.Collections.emptyList
+import java.util.concurrent.Executor
+import javax.inject.Singleton
+
+// corresponding Briar Android class in
+// briar/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java
+@Module(
+    includes = [
+        AccountModule::class,
+        IdentityModule::class,
+        CircumventionModule::class,
+        ClockModule::class,
+        DefaultBatteryManagerModule::class,
+        DefaultTaskSchedulerModule::class,
+        DefaultWakefulIoExecutorModule::class,
+        DesktopSecureRandomModule::class,
+        JavaNetworkModule::class,
+        JavaSystemModule::class,
+        SocksModule::class,
+        ViewModelModule::class,
+        AttachmentModule::class,
+    ]
+)
+internal class DesktopCoreModule(
+    private val appDir: Path,
+    private val socksPort: Int = DEFAULT_SOCKS_PORT,
+    private val controlPort: Int = DEFAULT_CONTROL_PORT,
+) {
+
+    @Provides
+    @Singleton
+    internal fun provideBriarUi(briarUi: BriarUiImpl): BriarUi = briarUi
+
+    @Provides
+    @Singleton
+    internal fun provideDatabaseConfig(): DatabaseConfig {
+        val dbDir = appDir.resolve("db")
+        val keyDir = appDir.resolve("key")
+        return DesktopDatabaseConfig(dbDir, keyDir)
+    }
+
+    @Provides
+    @Singleton
+    fun provideUnencryptedSettings(settings: UnencryptedSettingsImpl): UnencryptedSettings = settings
+
+    @Provides
+    @Singleton
+    // provide [UnencryptedSettings] singleton itself as provided above to use same object
+    fun provideUnencryptedSettingsReadOnly(settings: UnencryptedSettings): UnencryptedSettingsReadOnly = settings
+
+    @Provides
+    @Singleton
+    fun provideEncryptedSettings(settings: EncryptedSettingsImpl): EncryptedSettings = settings
+
+    @Provides
+    @Singleton
+    // provide [EncryptedSettings] singleton itself as provided above to use same object
+    fun provideEncryptedSettingsReadOnly(settings: EncryptedSettings): EncryptedSettingsReadOnly = settings
+
+    @Provides
+    @Singleton
+    @EventExecutor
+    fun provideEventExecutor(): Executor = provideUiExecutor()
+
+    @Provides
+    @Singleton
+    @UiExecutor
+    fun provideUiExecutor(): Executor = Dispatchers.Swing.asExecutor()
+
+    @Provides
+    @Singleton
+    fun provideBriarExecutors(briarExecutors: BriarExecutorsImpl): BriarExecutors = briarExecutors
+
+    @Provides
+    @TorDirectory
+    internal fun provideTorDirectory(): File =
+        appDir.resolve("tor").toFile()
+
+    @Provides
+    @Singleton
+    @TorSocksPort
+    internal fun provideTorSocksPort() = socksPort
+
+    @Provides
+    @Singleton
+    @TorControlPort
+    internal fun provideTorControlPort() = controlPort
+
+    @Provides
+    internal fun providePluginConfig(tor: UnixTorPluginFactory, lan: LanTcpPluginFactory): PluginConfig {
+        val duplex: List<DuplexPluginFactory> =
+            if (isLinux() || isMac()) listOf(tor, lan) else listOf(lan)
+        return object : PluginConfig {
+            override fun getDuplexFactories(): Collection<DuplexPluginFactory> = duplex
+            override fun getSimplexFactories(): Collection<SimplexPluginFactory> = emptyList()
+            override fun shouldPoll(): Boolean = true
+            override fun getTransportPreferences(): Map<TransportId, List<TransportId>> = emptyMap()
+        }
+    }
+
+    @Provides
+    @Singleton
+    fun provideConfiguration(configuration: ConfigurationImpl): Configuration = configuration
+
+    @Provides
+    @Singleton
+    internal fun provideImageCompressor(imageCompressor: ImageCompressorImpl): ImageCompressor = imageCompressor
+
+    @Provides
+    @Singleton
+    internal fun provideVisualNotificationProvider(): VisualNotificationProvider =
+        if (isLinux()) LibnotifyNotificationProvider else StubNotificationProvider
+
+    @Provides
+    @Singleton
+    internal fun provideSoundNotificationProvider() = SoundNotificationProvider
+
+    @Provides
+    @Singleton
+    internal fun provideMessageCounter(messageCounter: MessageCounterImpl): MessageCounter = messageCounter
+}
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/DesktopModule.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/DesktopModule.kt
index 2fe9d0556de97a3695869ad8be04d53f3a12ac79..ce1be9f598936f975cfe5b029cb176687f76d2d8 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/DesktopModule.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/DesktopModule.kt
@@ -20,160 +20,15 @@ package org.briarproject.briar.desktop
 
 import dagger.Module
 import dagger.Provides
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.asExecutor
-import kotlinx.coroutines.swing.Swing
-import org.briarproject.bramble.account.AccountModule
 import org.briarproject.bramble.api.FeatureFlags
-import org.briarproject.bramble.api.db.DatabaseConfig
-import org.briarproject.bramble.api.event.EventExecutor
-import org.briarproject.bramble.api.plugin.PluginConfig
-import org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_CONTROL_PORT
-import org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_SOCKS_PORT
-import org.briarproject.bramble.api.plugin.TorControlPort
-import org.briarproject.bramble.api.plugin.TorDirectory
-import org.briarproject.bramble.api.plugin.TorSocksPort
-import org.briarproject.bramble.api.plugin.TransportId
-import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory
-import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory
-import org.briarproject.bramble.battery.DefaultBatteryManagerModule
-import org.briarproject.bramble.network.JavaNetworkModule
-import org.briarproject.bramble.plugin.tcp.LanTcpPluginFactory
-import org.briarproject.bramble.plugin.tor.CircumventionModule
-import org.briarproject.bramble.plugin.tor.UnixTorPluginFactory
-import org.briarproject.bramble.socks.SocksModule
-import org.briarproject.bramble.system.ClockModule
-import org.briarproject.bramble.system.DefaultTaskSchedulerModule
-import org.briarproject.bramble.system.DefaultWakefulIoExecutorModule
-import org.briarproject.bramble.system.DesktopSecureRandomModule
-import org.briarproject.bramble.system.JavaSystemModule
-import org.briarproject.bramble.util.OsUtils.isLinux
-import org.briarproject.bramble.util.OsUtils.isMac
-import org.briarproject.briar.attachment.AttachmentModule
-import org.briarproject.briar.desktop.attachment.media.ImageCompressor
-import org.briarproject.briar.desktop.attachment.media.ImageCompressorImpl
-import org.briarproject.briar.desktop.notification.SoundNotificationProvider
-import org.briarproject.briar.desktop.notification.StubNotificationProvider
-import org.briarproject.briar.desktop.notification.VisualNotificationProvider
-import org.briarproject.briar.desktop.notification.linux.LibnotifyNotificationProvider
-import org.briarproject.briar.desktop.settings.Configuration
-import org.briarproject.briar.desktop.settings.ConfigurationImpl
-import org.briarproject.briar.desktop.settings.EncryptedSettings
-import org.briarproject.briar.desktop.settings.EncryptedSettingsImpl
-import org.briarproject.briar.desktop.settings.EncryptedSettingsReadOnly
-import org.briarproject.briar.desktop.settings.UnencryptedSettings
-import org.briarproject.briar.desktop.settings.UnencryptedSettingsImpl
-import org.briarproject.briar.desktop.settings.UnencryptedSettingsReadOnly
-import org.briarproject.briar.desktop.threading.BriarExecutors
-import org.briarproject.briar.desktop.threading.BriarExecutorsImpl
-import org.briarproject.briar.desktop.threading.UiExecutor
-import org.briarproject.briar.desktop.ui.BriarUi
-import org.briarproject.briar.desktop.ui.BriarUiImpl
-import org.briarproject.briar.desktop.ui.MessageCounter
-import org.briarproject.briar.desktop.ui.MessageCounterImpl
-import org.briarproject.briar.desktop.viewmodel.ViewModelModule
-import org.briarproject.briar.identity.IdentityModule
-import java.io.File
-import java.nio.file.Path
-import java.util.Collections.emptyList
-import java.util.concurrent.Executor
 import javax.inject.Singleton
 
 @Module(
     includes = [
-        AccountModule::class,
-        IdentityModule::class,
-        CircumventionModule::class,
-        ClockModule::class,
-        DefaultBatteryManagerModule::class,
-        DefaultTaskSchedulerModule::class,
-        DefaultWakefulIoExecutorModule::class,
-        DesktopSecureRandomModule::class,
-        JavaNetworkModule::class,
-        JavaSystemModule::class,
-        SocksModule::class,
-        ViewModelModule::class,
-        AttachmentModule::class,
+        DesktopCoreModule::class,
     ]
 )
-internal class DesktopModule(
-    private val appDir: Path,
-    private val socksPort: Int = DEFAULT_SOCKS_PORT,
-    private val controlPort: Int = DEFAULT_CONTROL_PORT
-) {
-
-    @Provides
-    @Singleton
-    internal fun provideBriarService(briarService: BriarUiImpl): BriarUi = briarService
-
-    @Provides
-    @Singleton
-    internal fun provideDatabaseConfig(): DatabaseConfig {
-        val dbDir = appDir.resolve("db")
-        val keyDir = appDir.resolve("key")
-        return DesktopDatabaseConfig(dbDir, keyDir)
-    }
-
-    @Provides
-    @Singleton
-    fun provideUnencryptedSettings(settings: UnencryptedSettingsImpl): UnencryptedSettings = settings
-
-    @Provides
-    @Singleton
-    // provide [UnencryptedSettings] singleton itself as provided above to use same object
-    fun provideUnencryptedSettingsReadOnly(settings: UnencryptedSettings): UnencryptedSettingsReadOnly = settings
-
-    @Provides
-    @Singleton
-    fun provideEncryptedSettings(settings: EncryptedSettingsImpl): EncryptedSettings = settings
-
-    @Provides
-    @Singleton
-    // provide [EncryptedSettings] singleton itself as provided above to use same object
-    fun provideEncryptedSettingsReadOnly(settings: EncryptedSettings): EncryptedSettingsReadOnly = settings
-
-    @Provides
-    @Singleton
-    @EventExecutor
-    fun provideEventExecutor(): Executor = provideUiExecutor()
-
-    @Provides
-    @Singleton
-    @UiExecutor
-    fun provideUiExecutor(): Executor = Dispatchers.Swing.asExecutor()
-
-    @Provides
-    @Singleton
-    fun provideBriarExecutors(briarExecutors: BriarExecutorsImpl): BriarExecutors = briarExecutors
-
-    @Provides
-    @TorDirectory
-    internal fun provideTorDirectory(): File {
-        return appDir.resolve("tor").toFile()
-    }
-
-    @Provides
-    @Singleton
-    @TorSocksPort
-    internal fun provideTorSocksPort() = socksPort
-
-    @Provides
-    @Singleton
-    @TorControlPort
-    internal fun provideTorControlPort() = controlPort
-
-    @Provides
-    internal fun providePluginConfig(tor: UnixTorPluginFactory, lan: LanTcpPluginFactory): PluginConfig {
-        val duplex: List<DuplexPluginFactory> =
-            if (isLinux() || isMac()) listOf(tor, lan) else listOf(lan)
-        return object : PluginConfig {
-            override fun getDuplexFactories(): Collection<DuplexPluginFactory> = duplex
-            override fun getSimplexFactories(): Collection<SimplexPluginFactory> = emptyList()
-            override fun shouldPoll(): Boolean = true
-            override fun getTransportPreferences(): Map<TransportId, List<TransportId>> = emptyMap()
-        }
-    }
-
+internal class DesktopModule {
     @Provides
     internal fun provideFeatureFlags(desktopFeatureFlags: DesktopFeatureFlags) = object : FeatureFlags {
         override fun shouldEnableImageAttachments() = true
@@ -193,27 +48,4 @@ internal class DesktopModule(
         override fun shouldEnableBlogs() = false
         override fun shouldEnableTransportSettings() = false
     }
-
-    @Provides
-    @Singleton
-    fun provideConfiguration(configuration: ConfigurationImpl): Configuration = configuration
-
-    @Provides
-    @Singleton
-    internal fun provideImageCompressor(imageCompressor: ImageCompressorImpl): ImageCompressor {
-        return imageCompressor
-    }
-
-    @Provides
-    @Singleton
-    internal fun provideVisualNotificationProvider(): VisualNotificationProvider =
-        if (isLinux()) LibnotifyNotificationProvider else StubNotificationProvider
-
-    @Provides
-    @Singleton
-    internal fun provideSoundNotificationProvider() = SoundNotificationProvider
-
-    @Provides
-    @Singleton
-    internal fun provideMessageCounter(messageCounter: MessageCounterImpl): MessageCounter = messageCounter
 }
diff --git a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/Main.kt b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/Main.kt
index 016c5fd441eabe00ddaaf0dfb6edeaee1cb210bf..1adf2da6931726ea72caa6a3efe5fbf4d4387c90 100644
--- a/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/Main.kt
+++ b/briar-desktop/src/main/kotlin/org/briarproject/briar/desktop/Main.kt
@@ -111,8 +111,8 @@ private class Main : CliktCommand(
 
         val dataDir = getDataDir()
         val app =
-            DaggerBriarDesktopApp.builder().desktopModule(
-                DesktopModule(dataDir, socksPort, controlPort)
+            DaggerBriarDesktopApp.builder().desktopCoreModule(
+                DesktopCoreModule(dataDir, socksPort, controlPort)
             ).build()
         // We need to load the eager singletons directly after making the
         // dependency graphs
diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/BriarDesktopTestApp.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/BriarDesktopTestApp.kt
index dc2c1e17c27223168c60de9030cee5d1b44ca7ba..e5795febfbcc2539704536acd86750f5117b9b9e 100644
--- a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/BriarDesktopTestApp.kt
+++ b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/BriarDesktopTestApp.kt
@@ -35,7 +35,6 @@ import org.briarproject.briar.api.introduction.IntroductionManager
 import org.briarproject.briar.api.test.TestDataCreator
 import org.briarproject.briar.desktop.testdata.DeterministicTestDataCreator
 import org.briarproject.briar.desktop.ui.BriarUi
-import java.security.SecureRandom
 import java.util.concurrent.Executor
 import javax.inject.Singleton
 
@@ -43,7 +42,7 @@ import javax.inject.Singleton
     modules = [
         BrambleCoreModule::class,
         BriarCoreModule::class,
-        DesktopTestModule::class
+        DesktopTestModule::class,
     ]
 )
 @Singleton
@@ -59,8 +58,6 @@ internal interface BriarDesktopTestApp : BrambleCoreEagerSingletons, BriarCoreEa
 
     fun getContactManager(): ContactManager
 
-    fun getSecureRandom(): SecureRandom
-
     fun getLifecycleManager(): LifecycleManager
 
     fun getShutdownManager(): ShutdownManager
diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/DesktopTestModule.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/DesktopTestModule.kt
index b37bfe2ef1bb30a7c3e10dc2b09a0246ae4e68f7..b89dbe7613064930a3e86021eaba5c975f0c7b83 100644
--- a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/DesktopTestModule.kt
+++ b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/DesktopTestModule.kt
@@ -20,166 +20,19 @@ package org.briarproject.briar.desktop
 
 import dagger.Module
 import dagger.Provides
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.asExecutor
-import kotlinx.coroutines.swing.Swing
-import org.briarproject.bramble.account.AccountModule
 import org.briarproject.bramble.api.FeatureFlags
-import org.briarproject.bramble.api.db.DatabaseConfig
-import org.briarproject.bramble.api.event.EventExecutor
-import org.briarproject.bramble.api.plugin.PluginConfig
-import org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_CONTROL_PORT
-import org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_SOCKS_PORT
-import org.briarproject.bramble.api.plugin.TorControlPort
-import org.briarproject.bramble.api.plugin.TorDirectory
-import org.briarproject.bramble.api.plugin.TorSocksPort
-import org.briarproject.bramble.api.plugin.TransportId
-import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory
-import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory
-import org.briarproject.bramble.battery.DefaultBatteryManagerModule
-import org.briarproject.bramble.network.JavaNetworkModule
-import org.briarproject.bramble.plugin.tcp.LanTcpPluginFactory
-import org.briarproject.bramble.plugin.tor.CircumventionModule
-import org.briarproject.bramble.plugin.tor.UnixTorPluginFactory
-import org.briarproject.bramble.socks.SocksModule
-import org.briarproject.bramble.system.ClockModule
-import org.briarproject.bramble.system.DefaultTaskSchedulerModule
-import org.briarproject.bramble.system.DefaultWakefulIoExecutorModule
-import org.briarproject.bramble.system.DesktopSecureRandomModule
-import org.briarproject.bramble.system.JavaSystemModule
-import org.briarproject.bramble.util.OsUtils.isLinux
-import org.briarproject.bramble.util.OsUtils.isMac
 import org.briarproject.briar.api.test.TestAvatarCreator
-import org.briarproject.briar.attachment.AttachmentModule
-import org.briarproject.briar.desktop.attachment.media.ImageCompressor
-import org.briarproject.briar.desktop.attachment.media.ImageCompressorImpl
-import org.briarproject.briar.desktop.notification.SoundNotificationProvider
-import org.briarproject.briar.desktop.notification.StubNotificationProvider
-import org.briarproject.briar.desktop.notification.VisualNotificationProvider
-import org.briarproject.briar.desktop.notification.linux.LibnotifyNotificationProvider
-import org.briarproject.briar.desktop.settings.Configuration
-import org.briarproject.briar.desktop.settings.ConfigurationImpl
-import org.briarproject.briar.desktop.settings.EncryptedSettings
-import org.briarproject.briar.desktop.settings.EncryptedSettingsImpl
-import org.briarproject.briar.desktop.settings.EncryptedSettingsReadOnly
-import org.briarproject.briar.desktop.settings.UnencryptedSettings
-import org.briarproject.briar.desktop.settings.UnencryptedSettingsImpl
-import org.briarproject.briar.desktop.settings.UnencryptedSettingsReadOnly
 import org.briarproject.briar.desktop.testdata.DeterministicTestDataCreator
 import org.briarproject.briar.desktop.testdata.DeterministicTestDataCreatorImpl
 import org.briarproject.briar.desktop.testdata.TestAvatarCreatorImpl
-import org.briarproject.briar.desktop.threading.BriarExecutors
-import org.briarproject.briar.desktop.threading.BriarExecutorsImpl
-import org.briarproject.briar.desktop.threading.UiExecutor
-import org.briarproject.briar.desktop.ui.BriarUi
-import org.briarproject.briar.desktop.ui.BriarUiImpl
-import org.briarproject.briar.desktop.ui.MessageCounter
-import org.briarproject.briar.desktop.ui.MessageCounterImpl
-import org.briarproject.briar.desktop.viewmodel.ViewModelModule
-import org.briarproject.briar.identity.IdentityModule
-import org.briarproject.briar.test.TestModule
-import java.io.File
-import java.nio.file.Path
-import java.util.Collections.emptyList
-import java.util.concurrent.Executor
 import javax.inject.Singleton
 
 @Module(
     includes = [
-        AccountModule::class,
-        IdentityModule::class,
-        CircumventionModule::class,
-        ClockModule::class,
-        DefaultBatteryManagerModule::class,
-        DefaultTaskSchedulerModule::class,
-        DefaultWakefulIoExecutorModule::class,
-        DesktopSecureRandomModule::class,
-        JavaNetworkModule::class,
-        JavaSystemModule::class,
-        SocksModule::class,
-        TestModule::class,
-        ViewModelModule::class,
-        AttachmentModule::class,
+        DesktopCoreModule::class,
     ]
 )
-internal class DesktopTestModule(
-    private val appDir: Path,
-    private val socksPort: Int = DEFAULT_SOCKS_PORT,
-    private val controlPort: Int = DEFAULT_CONTROL_PORT
-) {
-
-    @Provides
-    @Singleton
-    internal fun provideBriarService(briarService: BriarUiImpl): BriarUi = briarService
-
-    @Provides
-    @Singleton
-    internal fun provideDatabaseConfig(): DatabaseConfig {
-        val dbDir = appDir.resolve("db")
-        val keyDir = appDir.resolve("key")
-        return DesktopDatabaseConfig(dbDir, keyDir)
-    }
-
-    @Provides
-    @Singleton
-    // provide [UnencryptedSettings] singleton itself as provided above to use same object
-    fun provideUnencryptedSettingsReadOnly(settings: UnencryptedSettings): UnencryptedSettingsReadOnly = settings
-
-    @Provides
-    @Singleton
-    fun provideUnencryptedSettings(settings: UnencryptedSettingsImpl): UnencryptedSettings = settings
-
-    @Provides
-    @Singleton
-    fun provideEncryptedSettings(settings: EncryptedSettingsImpl): EncryptedSettings = settings
-
-    @Provides
-    @Singleton
-    // provide [EncryptedSettings] singleton itself as provided above to use same object
-    fun provideEncryptedSettingsReadOnly(settings: EncryptedSettings): EncryptedSettingsReadOnly = settings
-
-    @Provides
-    @Singleton
-    @EventExecutor
-    fun provideEventExecutor(): Executor = provideUiExecutor()
-
-    @Provides
-    @Singleton
-    @UiExecutor
-    fun provideUiExecutor(): Executor = Dispatchers.Swing.asExecutor()
-
-    @Provides
-    @Singleton
-    fun provideBriarExecutors(briarExecutors: BriarExecutorsImpl): BriarExecutors = briarExecutors
-
-    @Provides
-    @TorDirectory
-    internal fun provideTorDirectory(): File {
-        return appDir.resolve("tor").toFile()
-    }
-
-    @Provides
-    @Singleton
-    @TorSocksPort
-    internal fun provideTorSocksPort() = socksPort
-
-    @Provides
-    @Singleton
-    @TorControlPort
-    internal fun provideTorControlPort() = controlPort
-
-    @Provides
-    internal fun providePluginConfig(tor: UnixTorPluginFactory, lan: LanTcpPluginFactory): PluginConfig {
-        val duplex: List<DuplexPluginFactory> =
-            if (isLinux() || isMac()) listOf(tor, lan) else listOf(lan)
-        return object : PluginConfig {
-            override fun getDuplexFactories(): Collection<DuplexPluginFactory> = duplex
-            override fun getSimplexFactories(): Collection<SimplexPluginFactory> = emptyList()
-            override fun shouldPoll(): Boolean = true
-            override fun getTransportPreferences(): Map<TransportId, List<TransportId>> = emptyMap()
-        }
-    }
-
+internal class DesktopTestModule {
     @Provides
     internal fun provideFeatureFlags(desktopFeatureFlags: DesktopFeatureFlags) = object : FeatureFlags {
         override fun shouldEnableImageAttachments() = true
@@ -195,43 +48,18 @@ internal class DesktopTestModule(
     @Singleton
     internal fun provideDesktopFeatureFlags() = object : DesktopFeatureFlags {
         override fun shouldEnablePrivateGroups() = false
-        override fun shouldEnableForums() = false
+        override fun shouldEnableForums() = true
         override fun shouldEnableBlogs() = false
         override fun shouldEnableTransportSettings() = false
     }
 
     @Provides
     @Singleton
-    fun provideConfiguration(configuration: ConfigurationImpl): Configuration = configuration
-
-    @Provides
-    @Singleton
-    internal fun provideImageCompressor(imageCompressor: ImageCompressorImpl): ImageCompressor {
-        return imageCompressor
-    }
+    internal fun provideTestAvatarCreator(testAvatarCreator: TestAvatarCreatorImpl): TestAvatarCreator =
+        testAvatarCreator
 
     @Provides
     @Singleton
-    internal fun provideVisualNotificationProvider(): VisualNotificationProvider =
-        if (isLinux()) LibnotifyNotificationProvider else StubNotificationProvider
-
-    @Provides
-    @Singleton
-    internal fun provideSoundNotificationProvider() = SoundNotificationProvider
-
-    @Provides
-    @Singleton
-    internal fun provideMessageCounter(messageCounter: MessageCounterImpl): MessageCounter = messageCounter
-
-    @Provides
-    @Singleton
-    internal fun provideTestAvatarCreator(testAvatarCreator: TestAvatarCreatorImpl): TestAvatarCreator {
-        return testAvatarCreator
-    }
-
-    @Provides
-    @Singleton
-    internal fun provideDeterministicTestDataCreator(testDataCreator: DeterministicTestDataCreatorImpl): DeterministicTestDataCreator {
-        return testDataCreator
-    }
+    internal fun provideDeterministicTestDataCreator(testDataCreator: DeterministicTestDataCreatorImpl): DeterministicTestDataCreator =
+        testDataCreator
 }
diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/RunWithMultipleTemporaryAccounts.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/RunWithMultipleTemporaryAccounts.kt
index 6b391741d7b9522af969f6bfed950e9b703f02c9..7f79c397bbcfbddbce199dfdd2801ccdf41f03a4 100644
--- a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/RunWithMultipleTemporaryAccounts.kt
+++ b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/RunWithMultipleTemporaryAccounts.kt
@@ -36,7 +36,7 @@ import java.util.logging.Level.ALL
 
 internal class RunWithMultipleTemporaryAccounts(
     private val names: List<String>,
-    val customization: List<BriarDesktopTestApp>.() -> Unit
+    val customization: List<BriarDesktopTestApp>.() -> Unit,
 ) {
 
     companion object {
@@ -80,8 +80,8 @@ internal class RunWithMultipleTemporaryAccounts(
         LOG.i { "Using data directory '$dataDir'" }
 
         val app =
-            DaggerBriarDesktopTestApp.builder().desktopTestModule(
-                DesktopTestModule(dataDir, socksPort, controlPort)
+            DaggerBriarDesktopTestApp.builder().desktopCoreModule(
+                DesktopCoreModule(dataDir, socksPort, controlPort)
             ).build()
 
         app.getShutdownManager().addShutdownHook {
diff --git a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/RunWithTemporaryAccount.kt b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/RunWithTemporaryAccount.kt
index b300c321244a7357c2178e9a8492368d0cc08ac7..7ed82ca1b0bc41ee3dd30d0cd706bc6f8a7b246a 100644
--- a/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/RunWithTemporaryAccount.kt
+++ b/briar-desktop/src/test/kotlin/org/briarproject/briar/desktop/RunWithTemporaryAccount.kt
@@ -37,7 +37,7 @@ internal class RunWithTemporaryAccount(
     val createAccount: Boolean = true,
     val login: Boolean = true,
     val makeDirUnwritable: Boolean = false,
-    val customization: suspend BriarDesktopTestApp.() -> Unit = {}
+    val customization: suspend BriarDesktopTestApp.() -> Unit = {},
 ) {
 
     companion object {
@@ -58,8 +58,8 @@ internal class RunWithTemporaryAccount(
         }
 
         val app =
-            DaggerBriarDesktopTestApp.builder().desktopTestModule(
-                DesktopTestModule(dataDir)
+            DaggerBriarDesktopTestApp.builder().desktopCoreModule(
+                DesktopCoreModule(dataDir)
             ).build()
 
         app.getShutdownManager().addShutdownHook {