/* * Copyright © 2017-2025 WireGuard LLC. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ package com.wireguard.android.activity import android.content.Intent import android.os.Build import android.os.Bundle import android.view.LayoutInflater import android.view.MenuItem import android.view.View import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.commit import androidx.lifecycle.lifecycleScope import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import com.wireguard.android.Application import com.wireguard.android.QuickTileService import com.wireguard.android.R import com.wireguard.android.backend.WgQuickBackend import com.wireguard.android.preference.PreferencesPreferenceDataStore import com.wireguard.android.util.AdminKnobs import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext /** * Interface for changing application-global persistent settings. */ class SettingsActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) if (supportFragmentManager.findFragmentById(android.R.id.content) == null) { supportFragmentManager.commit { add(android.R.id.content, SettingsFragment()) } } } override fun onOptionsItemSelected(item: MenuItem): Boolean { if (item.itemId == android.R.id.home) { finish() return true } return super.onOptionsItemSelected(item) } class SettingsFragment : PreferenceFragmentCompat() { // Since this is pretty much abandoned by androidx, it never got updated for proper EdgeToEdge support, // which is enabled everywhere for API 35. So handle the insets manually here. override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { val view = super.onCreateView(inflater, container, savedInstanceState) view.fitsSystemWindows = true return view } override fun onCreatePreferences(savedInstanceState: Bundle?, key: String?) { preferenceManager.preferenceDataStore = PreferencesPreferenceDataStore(lifecycleScope, Application.getPreferencesDataStore()) addPreferencesFromResource(R.xml.preferences) preferenceScreen.initialExpandedChildrenCount = 5 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU || QuickTileService.isAdded) { val quickTile = preferenceManager.findPreference("quick_tile") quickTile?.parent?.removePreference(quickTile) --preferenceScreen.initialExpandedChildrenCount } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { val darkTheme = preferenceManager.findPreference("dark_theme") darkTheme?.parent?.removePreference(darkTheme) --preferenceScreen.initialExpandedChildrenCount } if (AdminKnobs.disableConfigExport) { val zipExporter = preferenceManager.findPreference("zip_exporter") zipExporter?.parent?.removePreference(zipExporter) } val wgQuickOnlyPrefs = arrayOf( preferenceManager.findPreference("tools_installer"), preferenceManager.findPreference("restore_on_boot"), preferenceManager.findPreference("multiple_tunnels") ).filterNotNull() wgQuickOnlyPrefs.forEach { it.isVisible = false } lifecycleScope.launch { if (Application.getBackend() is WgQuickBackend) { ++preferenceScreen.initialExpandedChildrenCount wgQuickOnlyPrefs.forEach { it.isVisible = true } } else { wgQuickOnlyPrefs.forEach { it.parent?.removePreference(it) } } } preferenceManager.findPreference("log_viewer")?.setOnPreferenceClickListener { startActivity(Intent(requireContext(), LogViewerActivity::class.java)) true } val kernelModuleEnabler = preferenceManager.findPreference("kernel_module_enabler") if (WgQuickBackend.hasKernelSupport()) { lifecycleScope.launch { if (Application.getBackend() !is WgQuickBackend) { try { withContext(Dispatchers.IO) { Application.getRootShell().start() } } catch (_: Throwable) { kernelModuleEnabler?.parent?.removePreference(kernelModuleEnabler) } } } } else { kernelModuleEnabler?.parent?.removePreference(kernelModuleEnabler) } } } }