aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ui/src/main/java/com/wireguard/android/preference/ToolsInstallerPreference.kt
diff options
context:
space:
mode:
Diffstat (limited to 'ui/src/main/java/com/wireguard/android/preference/ToolsInstallerPreference.kt')
-rw-r--r--ui/src/main/java/com/wireguard/android/preference/ToolsInstallerPreference.kt79
1 files changed, 79 insertions, 0 deletions
diff --git a/ui/src/main/java/com/wireguard/android/preference/ToolsInstallerPreference.kt b/ui/src/main/java/com/wireguard/android/preference/ToolsInstallerPreference.kt
new file mode 100644
index 00000000..b22048b5
--- /dev/null
+++ b/ui/src/main/java/com/wireguard/android/preference/ToolsInstallerPreference.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package com.wireguard.android.preference
+
+import android.content.Context
+import android.util.AttributeSet
+import androidx.preference.Preference
+import com.wireguard.android.Application
+import com.wireguard.android.R
+import com.wireguard.android.util.ToolsInstaller
+import com.wireguard.android.util.lifecycleScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+/**
+ * Preference implementing a button that asynchronously runs `ToolsInstaller` and displays the
+ * result as the preference summary.
+ */
+class ToolsInstallerPreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs) {
+ private var state = State.INITIAL
+ override fun getSummary() = context.getString(state.messageResourceId)
+
+ override fun getTitle() = context.getString(R.string.tools_installer_title)
+
+ override fun onAttached() {
+ super.onAttached()
+ lifecycleScope.launch {
+ try {
+ val state = withContext(Dispatchers.IO) { Application.getToolsInstaller().areInstalled() }
+ when {
+ state == ToolsInstaller.ERROR -> setState(State.INITIAL)
+ state and ToolsInstaller.YES == ToolsInstaller.YES -> setState(State.ALREADY)
+ state and (ToolsInstaller.MAGISK or ToolsInstaller.NO) == ToolsInstaller.MAGISK or ToolsInstaller.NO -> setState(State.INITIAL_MAGISK)
+ state and (ToolsInstaller.SYSTEM or ToolsInstaller.NO) == ToolsInstaller.SYSTEM or ToolsInstaller.NO -> setState(State.INITIAL_SYSTEM)
+ else -> setState(State.INITIAL)
+ }
+ } catch (_: Throwable) {
+ setState(State.INITIAL)
+ }
+ }
+ }
+
+ override fun onClick() {
+ setState(State.WORKING)
+ lifecycleScope.launch {
+ try {
+ val result = withContext(Dispatchers.IO) { Application.getToolsInstaller().install() }
+ when {
+ result and (ToolsInstaller.YES or ToolsInstaller.MAGISK) == ToolsInstaller.YES or ToolsInstaller.MAGISK -> setState(State.SUCCESS_MAGISK)
+ result and (ToolsInstaller.YES or ToolsInstaller.SYSTEM) == ToolsInstaller.YES or ToolsInstaller.SYSTEM -> setState(State.SUCCESS_SYSTEM)
+ else -> setState(State.FAILURE)
+ }
+ } catch (_: Throwable) {
+ setState(State.FAILURE)
+ }
+ }
+ }
+
+ private fun setState(state: State) {
+ if (this.state == state) return
+ this.state = state
+ if (isEnabled != state.shouldEnableView) isEnabled = state.shouldEnableView
+ notifyChanged()
+ }
+
+ private enum class State(val messageResourceId: Int, val shouldEnableView: Boolean) {
+ INITIAL(R.string.tools_installer_initial, true),
+ ALREADY(R.string.tools_installer_already, false),
+ FAILURE(R.string.tools_installer_failure, true),
+ WORKING(R.string.tools_installer_working, false),
+ INITIAL_SYSTEM(R.string.tools_installer_initial_system, true),
+ SUCCESS_SYSTEM(R.string.tools_installer_success_system, false),
+ INITIAL_MAGISK(R.string.tools_installer_initial_magisk, true),
+ SUCCESS_MAGISK(R.string.tools_installer_success_magisk, false);
+ }
+}