diff options
Diffstat (limited to 'ui/src/main/java/com/wireguard/android/fragment/BaseFragment.kt')
-rw-r--r-- | ui/src/main/java/com/wireguard/android/fragment/BaseFragment.kt | 94 |
1 files changed, 50 insertions, 44 deletions
diff --git a/ui/src/main/java/com/wireguard/android/fragment/BaseFragment.kt b/ui/src/main/java/com/wireguard/android/fragment/BaseFragment.kt index 82802623..2e551f83 100644 --- a/ui/src/main/java/com/wireguard/android/fragment/BaseFragment.kt +++ b/ui/src/main/java/com/wireguard/android/fragment/BaseFragment.kt @@ -1,66 +1,60 @@ /* - * 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.fragment import android.content.Context -import android.content.Intent import android.util.Log import android.view.View import android.widget.Toast +import androidx.activity.result.contract.ActivityResultContracts import androidx.databinding.DataBindingUtil import androidx.databinding.ViewDataBinding import androidx.fragment.app.Fragment +import androidx.lifecycle.lifecycleScope import com.google.android.material.snackbar.Snackbar import com.wireguard.android.Application import com.wireguard.android.R import com.wireguard.android.activity.BaseActivity import com.wireguard.android.activity.BaseActivity.OnSelectedTunnelChangedListener -import com.wireguard.android.backend.Backend import com.wireguard.android.backend.GoBackend import com.wireguard.android.backend.Tunnel import com.wireguard.android.databinding.TunnelDetailFragmentBinding import com.wireguard.android.databinding.TunnelListItemBinding import com.wireguard.android.model.ObservableTunnel import com.wireguard.android.util.ErrorMessages +import kotlinx.coroutines.launch /** * Base class for fragments that need to know the currently-selected tunnel. Only does anything when * attached to a `BaseActivity`. */ abstract class BaseFragment : Fragment(), OnSelectedTunnelChangedListener { - private var baseActivity: BaseActivity? = null private var pendingTunnel: ObservableTunnel? = null private var pendingTunnelUp: Boolean? = null + private val permissionActivityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { + val tunnel = pendingTunnel + val checked = pendingTunnelUp + if (tunnel != null && checked != null) + setTunnelStateWithPermissionsResult(tunnel, checked) + pendingTunnel = null + pendingTunnelUp = null + } + protected var selectedTunnel: ObservableTunnel? - get() = baseActivity?.selectedTunnel + get() = (activity as? BaseActivity)?.selectedTunnel protected set(tunnel) { - baseActivity?.selectedTunnel = tunnel + (activity as? BaseActivity)?.selectedTunnel = tunnel } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - if (requestCode == REQUEST_CODE_VPN_PERMISSION) { - if (pendingTunnel != null && pendingTunnelUp != null) setTunnelStateWithPermissionsResult(pendingTunnel!!, pendingTunnelUp!!) - pendingTunnel = null - pendingTunnelUp = null - } - } - override fun onAttach(context: Context) { super.onAttach(context) - if (context is BaseActivity) { - baseActivity = context - baseActivity?.addOnSelectedTunnelChangedListener(this) - } else { - baseActivity = null - } + (activity as? BaseActivity)?.addOnSelectedTunnelChangedListener(this) } override fun onDetach() { - baseActivity?.removeOnSelectedTunnelChangedListener(this) - baseActivity = null + (activity as? BaseActivity)?.removeOnSelectedTunnelChangedListener(this) super.onDetach() } @@ -70,14 +64,23 @@ abstract class BaseFragment : Fragment(), OnSelectedTunnelChangedListener { is TunnelListItemBinding -> binding.item else -> return } ?: return - Application.getBackendAsync().thenAccept { backend: Backend? -> - if (backend is GoBackend) { - val intent = GoBackend.VpnService.prepare(view.context) - if (intent != null) { - pendingTunnel = tunnel - pendingTunnelUp = checked - startActivityForResult(intent, REQUEST_CODE_VPN_PERMISSION) - return@thenAccept + val activity = activity ?: return + activity.lifecycleScope.launch { + if (Application.getBackend() is GoBackend) { + try { + val intent = GoBackend.VpnService.prepare(activity) + if (intent != null) { + pendingTunnel = tunnel + pendingTunnelUp = checked + permissionActivityResultLauncher.launch(intent) + return@launch + } + } catch (e: Throwable) { + val message = activity.getString(R.string.error_prepare, ErrorMessages[e]) + Snackbar.make(view, message, Snackbar.LENGTH_LONG) + .setAnchorView(view.findViewById(R.id.create_fab)) + .show() + Log.e(TAG, message, e) } } setTunnelStateWithPermissionsResult(tunnel, checked) @@ -85,24 +88,27 @@ abstract class BaseFragment : Fragment(), OnSelectedTunnelChangedListener { } private fun setTunnelStateWithPermissionsResult(tunnel: ObservableTunnel, checked: Boolean) { - tunnel.setStateAsync(Tunnel.State.of(checked)).whenComplete { _, throwable -> - if (throwable == null) return@whenComplete - val error = ErrorMessages[throwable] - val messageResId = if (checked) R.string.error_up else R.string.error_down - val message = requireContext().getString(messageResId, error) - val view = view - if (view != null) - Snackbar.make(view, message, Snackbar.LENGTH_LONG) - .setAnchorView(view.findViewById<View>(R.id.create_fab)) + val activity = activity ?: return + activity.lifecycleScope.launch { + try { + tunnel.setStateAsync(Tunnel.State.of(checked)) + } catch (e: Throwable) { + val error = ErrorMessages[e] + val messageResId = if (checked) R.string.error_up else R.string.error_down + val message = activity.getString(messageResId, error) + val view = view + if (view != null) + Snackbar.make(view, message, Snackbar.LENGTH_LONG) + .setAnchorView(view.findViewById(R.id.create_fab)) .show() - else - Toast.makeText(requireContext(), message, Toast.LENGTH_LONG).show() - Log.e(TAG, message, throwable) + else + Toast.makeText(activity, message, Toast.LENGTH_LONG).show() + Log.e(TAG, message, e) + } } } companion object { - private const val REQUEST_CODE_VPN_PERMISSION = 23491 private const val TAG = "WireGuard/BaseFragment" } } |