diff options
Diffstat (limited to 'ui/src/main/java/com/wireguard/android/Application.kt')
-rw-r--r-- | ui/src/main/java/com/wireguard/android/Application.kt | 156 |
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 { |