aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ui/src/main/java/com/wireguard/android/Application.kt
diff options
context:
space:
mode:
Diffstat (limited to 'ui/src/main/java/com/wireguard/android/Application.kt')
-rw-r--r--ui/src/main/java/com/wireguard/android/Application.kt156
1 files changed, 77 insertions, 79 deletions
diff --git a/ui/src/main/java/com/wireguard/android/Application.kt b/ui/src/main/java/com/wireguard/android/Application.kt
index d533028f..74eaccf8 100644
--- a/ui/src/main/java/com/wireguard/android/Application.kt
+++ b/ui/src/main/java/com/wireguard/android/Application.kt
@@ -1,43 +1,51 @@
/*
- * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
+ * Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android
import android.content.Context
import android.content.Intent
-import android.content.SharedPreferences
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener
-import android.os.AsyncTask
import android.os.Build
-import android.os.Handler
-import android.os.Looper
import android.os.StrictMode
+import android.os.StrictMode.ThreadPolicy
import android.os.StrictMode.VmPolicy
import android.util.Log
import androidx.appcompat.app.AppCompatDelegate
-import androidx.preference.PreferenceManager
+import androidx.datastore.core.DataStore
+import androidx.datastore.preferences.core.PreferenceDataStoreFactory
+import androidx.datastore.preferences.core.Preferences
+import androidx.datastore.preferences.preferencesDataStoreFile
+import com.google.android.material.color.DynamicColors
import com.wireguard.android.backend.Backend
import com.wireguard.android.backend.GoBackend
import com.wireguard.android.backend.WgQuickBackend
import com.wireguard.android.configStore.FileConfigStore
import com.wireguard.android.model.TunnelManager
-import com.wireguard.android.util.AsyncWorker
-import com.wireguard.android.util.ExceptionLoggers
-import com.wireguard.android.util.ModuleLoader
+import com.wireguard.android.updater.Updater
import com.wireguard.android.util.RootShell
import com.wireguard.android.util.ToolsInstaller
-import java9.util.concurrent.CompletableFuture
+import com.wireguard.android.util.UserKnobs
+import com.wireguard.android.util.applicationScope
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
import java.lang.ref.WeakReference
import java.util.Locale
-class Application : android.app.Application(), OnSharedPreferenceChangeListener {
- private val futureBackend = CompletableFuture<Backend>()
- private lateinit var asyncWorker: AsyncWorker
+class Application : android.app.Application() {
+ private val futureBackend = CompletableDeferred<Backend>()
+ private val coroutineScope = CoroutineScope(Job() + Dispatchers.Main.immediate)
private var backend: Backend? = null
- private lateinit var moduleLoader: ModuleLoader
private lateinit var rootShell: RootShell
- private lateinit var sharedPreferences: SharedPreferences
+ private lateinit var preferencesDataStore: DataStore<Preferences>
private lateinit var toolsInstaller: ToolsInstaller
private lateinit var tunnelManager: TunnelManager
@@ -51,38 +59,73 @@ class Application : android.app.Application(), OnSharedPreferenceChangeListener
startActivity(intent)
System.exit(0)
}
- if (BuildConfig.DEBUG) {
- StrictMode.setVmPolicy(VmPolicy.Builder().detectAll().penaltyLog().build())
+ }
+
+ private suspend fun determineBackend(): Backend {
+ var backend: Backend? = null
+ if (UserKnobs.enableKernelModule.first() && WgQuickBackend.hasKernelSupport()) {
+ try {
+ rootShell.start()
+ val wgQuickBackend = WgQuickBackend(applicationContext, rootShell, toolsInstaller)
+ wgQuickBackend.setMultipleTunnels(UserKnobs.multipleTunnels.first())
+ backend = wgQuickBackend
+ UserKnobs.multipleTunnels.onEach {
+ wgQuickBackend.setMultipleTunnels(it)
+ }.launchIn(coroutineScope)
+ } catch (ignored: Exception) {
+ }
+ }
+ if (backend == null) {
+ backend = GoBackend(applicationContext)
+ GoBackend.setAlwaysOnCallback { get().applicationScope.launch { get().tunnelManager.restoreState(true) } }
}
+ return backend
}
override fun onCreate() {
Log.i(TAG, USER_AGENT)
super.onCreate()
- asyncWorker = AsyncWorker(AsyncTask.SERIAL_EXECUTOR, Handler(Looper.getMainLooper()))
+ DynamicColors.applyToActivitiesIfAvailable(this)
rootShell = RootShell(applicationContext)
toolsInstaller = ToolsInstaller(applicationContext, rootShell)
- moduleLoader = ModuleLoader(applicationContext, rootShell, USER_AGENT)
- sharedPreferences = PreferenceManager.getDefaultSharedPreferences(applicationContext)
+ preferencesDataStore = PreferenceDataStoreFactory.create { applicationContext.preferencesDataStoreFile("settings") }
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
- AppCompatDelegate.setDefaultNightMode(
- if (sharedPreferences.getBoolean("dark_theme", false)) AppCompatDelegate.MODE_NIGHT_YES else AppCompatDelegate.MODE_NIGHT_NO)
+ runBlocking {
+ AppCompatDelegate.setDefaultNightMode(if (UserKnobs.darkTheme.first()) AppCompatDelegate.MODE_NIGHT_YES else AppCompatDelegate.MODE_NIGHT_NO)
+ }
+ UserKnobs.darkTheme.onEach {
+ val newMode = if (it) {
+ AppCompatDelegate.MODE_NIGHT_YES
+ } else {
+ AppCompatDelegate.MODE_NIGHT_NO
+ }
+ if (AppCompatDelegate.getDefaultNightMode() != newMode) {
+ AppCompatDelegate.setDefaultNightMode(newMode)
+ }
+ }.launchIn(coroutineScope)
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}
tunnelManager = TunnelManager(FileConfigStore(applicationContext))
tunnelManager.onCreate()
- asyncWorker.supplyAsync(Companion::getBackend).thenAccept { futureBackend.complete(it) }
- sharedPreferences.registerOnSharedPreferenceChangeListener(this)
- }
+ coroutineScope.launch(Dispatchers.IO) {
+ try {
+ backend = determineBackend()
+ futureBackend.complete(backend!!)
+ } catch (e: Throwable) {
+ Log.e(TAG, Log.getStackTraceString(e))
+ }
+ }
+ Updater.monitorForUpdates()
- override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
- if ("multiple_tunnels" == key && backend != null && backend is WgQuickBackend)
- (backend as WgQuickBackend).setMultipleTunnels(sharedPreferences.getBoolean(key, false))
+ if (BuildConfig.DEBUG) {
+ StrictMode.setVmPolicy(VmPolicy.Builder().detectAll().penaltyLog().build())
+ StrictMode.setThreadPolicy(ThreadPolicy.Builder().detectAll().penaltyLog().build())
+ }
}
override fun onTerminate() {
- sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
+ coroutineScope.cancel()
super.onTerminate()
}
@@ -91,66 +134,21 @@ class Application : android.app.Application(), OnSharedPreferenceChangeListener
private const val TAG = "WireGuard/Application"
private lateinit var weakSelf: WeakReference<Application>
- @JvmStatic
fun get(): Application {
return weakSelf.get()!!
}
- @JvmStatic
- fun getAsyncWorker() = get().asyncWorker
-
- @JvmStatic
- fun getBackend(): Backend {
- val app = get()
- synchronized(app.futureBackend) {
- if (app.backend == null) {
- var backend: Backend? = null
- var didStartRootShell = false
- if (!ModuleLoader.isModuleLoaded() && app.moduleLoader.moduleMightExist()) {
- try {
- app.rootShell.start()
- didStartRootShell = true
- app.moduleLoader.loadModule()
- } catch (ignored: Exception) {
- }
- }
- if (!app.sharedPreferences.getBoolean("disable_kernel_module", false) && ModuleLoader.isModuleLoaded()) {
- try {
- if (!didStartRootShell)
- app.rootShell.start()
- val wgQuickBackend = WgQuickBackend(app.applicationContext, app.rootShell, app.toolsInstaller)
- wgQuickBackend.setMultipleTunnels(app.sharedPreferences.getBoolean("multiple_tunnels", false))
- backend = wgQuickBackend
- } catch (ignored: Exception) {
- }
- }
- if (backend == null) {
- backend = GoBackend(app.applicationContext)
- GoBackend.setAlwaysOnCallback { get().tunnelManager.restoreState(true).whenComplete(ExceptionLoggers.D) }
- }
- app.backend = backend
- }
- return app.backend!!
- }
- }
-
- @JvmStatic
- fun getBackendAsync() = get().futureBackend
+ suspend fun getBackend() = get().futureBackend.await()
- @JvmStatic
- fun getModuleLoader() = get().moduleLoader
-
- @JvmStatic
fun getRootShell() = get().rootShell
- @JvmStatic
- fun getSharedPreferences() = get().sharedPreferences
+ fun getPreferencesDataStore() = get().preferencesDataStore
- @JvmStatic
fun getToolsInstaller() = get().toolsInstaller
- @JvmStatic
fun getTunnelManager() = get().tunnelManager
+
+ fun getCoroutineScope() = get().coroutineScope
}
init {