mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
refactor(android): Refactor navigation and session functionality (#2469)
This PR refactors navigation to fix nav issues and session implementation to fix: Fixes #2300 Fixes #2186 --------- Signed-off-by: Pratik Velani <pratikvelani@gmail.com>
This commit is contained in:
@@ -72,6 +72,10 @@
|
||||
android:name="dev.firezone.android.features.permission.vpn.ui.VpnPermissionActivity"
|
||||
android:exported="false" />
|
||||
|
||||
<activity
|
||||
android:name="dev.firezone.android.features.session.ui.SessionActivity"
|
||||
android:exported="false" />
|
||||
|
||||
<service
|
||||
android:name="dev.firezone.android.tunnel.TunnelService"
|
||||
android:exported="true"
|
||||
|
||||
@@ -3,7 +3,6 @@ package dev.firezone.android.features.applink.ui
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
@@ -29,17 +28,14 @@ class AppLinkHandlerActivity : AppCompatActivity(R.layout.activity_app_link_hand
|
||||
viewModel.actionLiveData.observe(this) { action ->
|
||||
when (action) {
|
||||
AppLinkViewModel.ViewAction.AuthFlowComplete -> {
|
||||
// TODO: Continue starting the session showing sessionFragment
|
||||
Log.d("AppLinkHandlerActivity", "AuthFlowComplete")
|
||||
|
||||
val intent = Intent(this@AppLinkHandlerActivity, MainActivity::class.java)
|
||||
this@AppLinkHandlerActivity.startActivity(intent)
|
||||
this@AppLinkHandlerActivity.finish()
|
||||
startActivity(
|
||||
Intent(this@AppLinkHandlerActivity, MainActivity::class.java).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
|
||||
},
|
||||
)
|
||||
finish()
|
||||
}
|
||||
AppLinkViewModel.ViewAction.ShowError -> showError()
|
||||
else -> {
|
||||
Log.d("AppLinkHandlerActivity", "Unhandled action: $action")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ internal class AppLinkViewModel
|
||||
}
|
||||
intent.data?.getQueryParameter(QUERY_CLIENT_AUTH_TOKEN)?.let { token ->
|
||||
if (token.isNotBlank()) {
|
||||
// TODO: Don't log auth token
|
||||
Log.d("AppLinkViewModel", "Found valid auth token in response")
|
||||
saveTokenUseCase(token).collect()
|
||||
} else {
|
||||
|
||||
@@ -38,7 +38,7 @@ class AuthActivity : AppCompatActivity(R.layout.activity_auth) {
|
||||
viewModel.actionLiveData.observe(this) { action ->
|
||||
when (action) {
|
||||
is AuthViewModel.ViewAction.LaunchAuthFlow -> setupWebView(action.url)
|
||||
is AuthViewModel.ViewAction.NavigateToSignInFragment -> {
|
||||
is AuthViewModel.ViewAction.NavigateToSignIn -> {
|
||||
navigateToSignIn()
|
||||
}
|
||||
is AuthViewModel.ViewAction.ShowError -> showError()
|
||||
|
||||
@@ -39,7 +39,7 @@ internal class AuthViewModel
|
||||
|
||||
actionMutableLiveData.postValue(
|
||||
if (authFlowLaunched || config.token != null) {
|
||||
ViewAction.NavigateToSignInFragment
|
||||
ViewAction.NavigateToSignIn
|
||||
} else {
|
||||
authFlowLaunched = true
|
||||
ViewAction.LaunchAuthFlow(
|
||||
@@ -59,7 +59,7 @@ internal class AuthViewModel
|
||||
internal sealed class ViewAction {
|
||||
data class LaunchAuthFlow(val url: String) : ViewAction()
|
||||
|
||||
object NavigateToSignInFragment : ViewAction()
|
||||
object NavigateToSignIn : ViewAction()
|
||||
|
||||
object ShowError : ViewAction()
|
||||
}
|
||||
|
||||
@@ -3,11 +3,9 @@ package dev.firezone.android.features.session.ui
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
@@ -17,41 +15,38 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.firezone.android.R
|
||||
import dev.firezone.android.core.presentation.MainActivity
|
||||
import dev.firezone.android.core.utils.ClipboardUtils
|
||||
import dev.firezone.android.databinding.FragmentSessionBinding
|
||||
import dev.firezone.android.databinding.ActivitySessionBinding
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@AndroidEntryPoint
|
||||
internal class SessionFragment : Fragment(R.layout.fragment_session) {
|
||||
private lateinit var binding: FragmentSessionBinding
|
||||
internal class SessionActivity : AppCompatActivity() {
|
||||
private lateinit var binding: ActivitySessionBinding
|
||||
private val viewModel: SessionViewModel by viewModels()
|
||||
|
||||
private val resourcesAdapter: ResourcesAdapter =
|
||||
ResourcesAdapter { resource ->
|
||||
ClipboardUtils.copyToClipboard(requireContext(), resource.name, resource.address)
|
||||
ClipboardUtils.copyToClipboard(this@SessionActivity, resource.name, resource.address)
|
||||
}
|
||||
|
||||
override fun onViewCreated(
|
||||
view: View,
|
||||
savedInstanceState: Bundle?,
|
||||
) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding = FragmentSessionBinding.bind(view)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivitySessionBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
setupViews()
|
||||
setupObservers()
|
||||
Log.d("SessionFragment", "Starting session...")
|
||||
viewModel.startSession()
|
||||
viewModel.connect(this@SessionActivity)
|
||||
}
|
||||
|
||||
private fun setupViews() {
|
||||
binding.btSignOut.setOnClickListener {
|
||||
viewModel.onDisconnect()
|
||||
viewModel.disconnect()
|
||||
}
|
||||
|
||||
val layoutManager = LinearLayoutManager(requireContext())
|
||||
val layoutManager = LinearLayoutManager(this@SessionActivity)
|
||||
val dividerItemDecoration =
|
||||
DividerItemDecoration(
|
||||
requireContext(),
|
||||
this@SessionActivity,
|
||||
layoutManager.orientation,
|
||||
)
|
||||
binding.resourcesList.addItemDecoration(dividerItemDecoration)
|
||||
@@ -60,15 +55,13 @@ internal class SessionFragment : Fragment(R.layout.fragment_session) {
|
||||
}
|
||||
|
||||
private fun setupObservers() {
|
||||
viewModel.actionLiveData.observe(viewLifecycleOwner) { action ->
|
||||
viewModel.actionLiveData.observe(this@SessionActivity) { action ->
|
||||
when (action) {
|
||||
SessionViewModel.ViewAction.NavigateToSignInFragment -> {
|
||||
requireActivity().run {
|
||||
startActivity(
|
||||
Intent(this, MainActivity::class.java),
|
||||
)
|
||||
finish()
|
||||
}
|
||||
SessionViewModel.ViewAction.NavigateToSignIn -> {
|
||||
startActivity(
|
||||
Intent(this, MainActivity::class.java),
|
||||
)
|
||||
finish()
|
||||
}
|
||||
SessionViewModel.ViewAction.ShowError -> showError()
|
||||
}
|
||||
@@ -86,7 +79,7 @@ internal class SessionFragment : Fragment(R.layout.fragment_session) {
|
||||
}
|
||||
|
||||
private fun showError() {
|
||||
AlertDialog.Builder(requireContext())
|
||||
AlertDialog.Builder(this@SessionActivity)
|
||||
.setTitle(R.string.error_dialog_title)
|
||||
.setMessage(R.string.error_dialog_message)
|
||||
.setPositiveButton(
|
||||
@@ -1,6 +1,7 @@
|
||||
/* Licensed under Apache 2.0 (C) 2023 Firezone, Inc. */
|
||||
package dev.firezone.android.features.session.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
@@ -8,7 +9,9 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dev.firezone.android.tunnel.TunnelManager
|
||||
import dev.firezone.android.tunnel.TunnelService
|
||||
import dev.firezone.android.tunnel.callback.TunnelListener
|
||||
import dev.firezone.android.tunnel.data.TunnelRepository
|
||||
import dev.firezone.android.tunnel.model.Resource
|
||||
import dev.firezone.android.tunnel.model.Tunnel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -21,6 +24,7 @@ internal class SessionViewModel
|
||||
@Inject
|
||||
constructor(
|
||||
private val tunnelManager: TunnelManager,
|
||||
private val tunnelRepository: TunnelRepository,
|
||||
) : ViewModel() {
|
||||
private val _uiState = MutableStateFlow(UiState())
|
||||
val uiState: StateFlow<UiState> = _uiState
|
||||
@@ -31,7 +35,20 @@ internal class SessionViewModel
|
||||
private val tunnelListener =
|
||||
object : TunnelListener {
|
||||
override fun onTunnelStateUpdate(state: Tunnel.State) {
|
||||
TODO("Not yet implemented")
|
||||
when (state) {
|
||||
Tunnel.State.Down -> {
|
||||
onDisconnect()
|
||||
}
|
||||
Tunnel.State.Closed -> {
|
||||
onClosed()
|
||||
}
|
||||
else -> {
|
||||
_uiState.value =
|
||||
_uiState.value.copy(
|
||||
state = state,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResourcesUpdate(resources: List<Resource>) {
|
||||
@@ -48,10 +65,23 @@ internal class SessionViewModel
|
||||
}
|
||||
}
|
||||
|
||||
fun startSession() {
|
||||
fun connect(context: Context) {
|
||||
viewModelScope.launch {
|
||||
tunnelManager.addListener(tunnelListener)
|
||||
tunnelManager.connect()
|
||||
|
||||
val isServiceRunning = TunnelService.isRunning(context)
|
||||
if (!isServiceRunning ||
|
||||
tunnelRepository.getState() == Tunnel.State.Down ||
|
||||
tunnelRepository.getState() == Tunnel.State.Closed
|
||||
) {
|
||||
tunnelManager.connect()
|
||||
} else {
|
||||
_uiState.value =
|
||||
_uiState.value.copy(
|
||||
state = tunnelRepository.getState(),
|
||||
resources = tunnelRepository.getResources(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,18 +91,26 @@ internal class SessionViewModel
|
||||
tunnelManager.removeListener(tunnelListener)
|
||||
}
|
||||
|
||||
fun onDisconnect() {
|
||||
fun disconnect() {
|
||||
tunnelManager.disconnect()
|
||||
}
|
||||
|
||||
private fun onDisconnect() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
private fun onClosed() {
|
||||
tunnelManager.removeListener(tunnelListener)
|
||||
actionMutableLiveData.postValue(ViewAction.NavigateToSignInFragment)
|
||||
actionMutableLiveData.postValue(ViewAction.NavigateToSignIn)
|
||||
}
|
||||
|
||||
internal data class UiState(
|
||||
val state: Tunnel.State = Tunnel.State.Down,
|
||||
val resources: List<Resource>? = null,
|
||||
)
|
||||
|
||||
internal sealed class ViewAction {
|
||||
object NavigateToSignInFragment : ViewAction()
|
||||
object NavigateToSignIn : ViewAction()
|
||||
|
||||
object ShowError : ViewAction()
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ internal class SettingsFragment : Fragment(R.layout.fragment_settings) {
|
||||
private fun setupActionObservers() {
|
||||
viewModel.actionLiveData.observe(viewLifecycleOwner) { action ->
|
||||
when (action) {
|
||||
is SettingsViewModel.ViewAction.NavigateToSignInFragment ->
|
||||
is SettingsViewModel.ViewAction.NavigateToSignIn ->
|
||||
findNavController().navigate(
|
||||
R.id.signInFragment,
|
||||
)
|
||||
|
||||
@@ -40,7 +40,7 @@ internal class SettingsViewModel
|
||||
fun onSaveSettingsCompleted() {
|
||||
viewModelScope.launch {
|
||||
saveAccountIdUseCase(input).collect {
|
||||
actionMutableLiveData.postValue(ViewAction.NavigateToSignInFragment)
|
||||
actionMutableLiveData.postValue(ViewAction.NavigateToSignIn)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,7 +59,7 @@ internal class SettingsViewModel
|
||||
}
|
||||
|
||||
internal sealed class ViewAction {
|
||||
object NavigateToSignInFragment : ViewAction()
|
||||
object NavigateToSignIn : ViewAction()
|
||||
|
||||
data class FillAccountId(val value: String) : ViewAction()
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.firezone.android.R
|
||||
import dev.firezone.android.databinding.FragmentSignInBinding
|
||||
import dev.firezone.android.features.auth.ui.AuthActivity
|
||||
import dev.firezone.android.features.splash.ui.SplashFragmentDirections
|
||||
|
||||
@AndroidEntryPoint
|
||||
internal class SignInFragment : Fragment(R.layout.fragment_sign_in) {
|
||||
@@ -37,10 +36,11 @@ internal class SignInFragment : Fragment(R.layout.fragment_sign_in) {
|
||||
AuthActivity::class.java,
|
||||
),
|
||||
)
|
||||
requireActivity().finish()
|
||||
}
|
||||
btSettings.setOnClickListener {
|
||||
findNavController().navigate(
|
||||
SplashFragmentDirections.navigateToSettingsFragment(),
|
||||
R.id.settingsFragment,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* Licensed under Apache 2.0 (C) 2023 Firezone, Inc. */
|
||||
package dev.firezone.android.features.splash.ui
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
@@ -9,6 +10,7 @@ import androidx.navigation.fragment.findNavController
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.firezone.android.R
|
||||
import dev.firezone.android.databinding.FragmentSplashBinding
|
||||
import dev.firezone.android.features.session.ui.SessionActivity
|
||||
|
||||
@AndroidEntryPoint
|
||||
internal class SplashFragment : Fragment(R.layout.fragment_splash) {
|
||||
@@ -37,17 +39,19 @@ internal class SplashFragment : Fragment(R.layout.fragment_splash) {
|
||||
findNavController().navigate(
|
||||
R.id.vpnPermissionActivity,
|
||||
)
|
||||
SplashViewModel.ViewAction.NavigateToSignInFragment ->
|
||||
SplashViewModel.ViewAction.NavigateToSignIn ->
|
||||
findNavController().navigate(
|
||||
R.id.signInFragment,
|
||||
)
|
||||
SplashViewModel.ViewAction.NavigateToSettingsFragment ->
|
||||
SplashViewModel.ViewAction.NavigateToSettings ->
|
||||
findNavController().navigate(
|
||||
R.id.settingsFragment,
|
||||
)
|
||||
SplashViewModel.ViewAction.NavigateToSessionFragment ->
|
||||
findNavController().navigate(
|
||||
R.id.sessionFragment,
|
||||
SplashViewModel.ViewAction.NavigateToSession ->
|
||||
startActivity(
|
||||
Intent(requireContext(), SessionActivity::class.java).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,11 +37,11 @@ internal class SplashViewModel
|
||||
}
|
||||
.collect { user ->
|
||||
if (user.accountId.isNullOrEmpty()) {
|
||||
actionMutableLiveData.postValue(ViewAction.NavigateToSettingsFragment)
|
||||
actionMutableLiveData.postValue(ViewAction.NavigateToSettings)
|
||||
} else if (user.token.isNullOrBlank()) {
|
||||
actionMutableLiveData.postValue(ViewAction.NavigateToSignInFragment)
|
||||
actionMutableLiveData.postValue(ViewAction.NavigateToSignIn)
|
||||
} else {
|
||||
actionMutableLiveData.postValue(ViewAction.NavigateToSessionFragment)
|
||||
actionMutableLiveData.postValue(ViewAction.NavigateToSession)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,8 +54,8 @@ internal class SplashViewModel
|
||||
|
||||
internal sealed class ViewAction {
|
||||
object NavigateToVpnPermission : ViewAction()
|
||||
object NavigateToSettingsFragment : ViewAction()
|
||||
object NavigateToSignInFragment : ViewAction()
|
||||
object NavigateToSessionFragment : ViewAction()
|
||||
object NavigateToSettings : ViewAction()
|
||||
object NavigateToSignIn : ViewAction()
|
||||
object NavigateToSession : ViewAction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import android.util.Log
|
||||
import dev.firezone.android.core.data.PreferenceRepository
|
||||
import dev.firezone.android.tunnel.callback.TunnelListener
|
||||
import dev.firezone.android.tunnel.data.TunnelRepository
|
||||
import dev.firezone.android.tunnel.model.Tunnel
|
||||
import java.lang.ref.WeakReference
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@@ -24,10 +23,17 @@ internal class TunnelManager
|
||||
private val listeners: MutableSet<WeakReference<TunnelListener>> = mutableSetOf()
|
||||
|
||||
private val tunnelRepositoryListener =
|
||||
SharedPreferences.OnSharedPreferenceChangeListener { _, s ->
|
||||
if (s == TunnelRepository.RESOURCES_KEY) {
|
||||
listeners.forEach {
|
||||
it.get()?.onResourcesUpdate(tunnelRepository.getResources())
|
||||
SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
|
||||
when (key) {
|
||||
TunnelRepository.STATE_KEY -> {
|
||||
listeners.forEach {
|
||||
it.get()?.onTunnelStateUpdate(tunnelRepository.getState())
|
||||
}
|
||||
}
|
||||
TunnelRepository.RESOURCES_KEY -> {
|
||||
listeners.forEach {
|
||||
it.get()?.onResourcesUpdate(tunnelRepository.getResources())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,7 +49,6 @@ internal class TunnelManager
|
||||
}
|
||||
|
||||
tunnelRepository.addListener(tunnelRepositoryListener)
|
||||
tunnelRepository.setState(Tunnel.State.Connecting)
|
||||
}
|
||||
|
||||
fun removeListener(listener: TunnelListener) {
|
||||
@@ -65,6 +70,7 @@ internal class TunnelManager
|
||||
|
||||
fun disconnect() {
|
||||
stopVPNService()
|
||||
clearSessionData()
|
||||
}
|
||||
|
||||
private fun startVPNService() {
|
||||
@@ -77,8 +83,11 @@ internal class TunnelManager
|
||||
val intent = Intent(appContext, TunnelService::class.java)
|
||||
intent.action = TunnelService.ACTION_DISCONNECT
|
||||
appContext.startService(intent)
|
||||
tunnelRepository.clearAll()
|
||||
}
|
||||
|
||||
private fun clearSessionData() {
|
||||
preferenceRepository.clearToken()
|
||||
tunnelRepository.clearAll()
|
||||
}
|
||||
|
||||
internal companion object {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
/* Licensed under Apache 2.0 (C) 2023 Firezone, Inc. */
|
||||
package dev.firezone.android.tunnel
|
||||
|
||||
import android.app.ActivityManager
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.VpnService
|
||||
import android.system.OsConstants
|
||||
@@ -16,6 +18,7 @@ import com.squareup.moshi.adapter
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.firezone.android.BuildConfig
|
||||
import dev.firezone.android.R
|
||||
import dev.firezone.android.core.data.PreferenceRepository
|
||||
import dev.firezone.android.core.domain.preference.GetConfigUseCase
|
||||
import dev.firezone.android.core.presentation.MainActivity
|
||||
import dev.firezone.android.tunnel.callback.ConnlibCallback
|
||||
@@ -38,11 +41,16 @@ class TunnelService : VpnService() {
|
||||
@Inject
|
||||
internal lateinit var tunnelRepository: TunnelRepository
|
||||
|
||||
@Inject
|
||||
internal lateinit var preferenceRepository: PreferenceRepository
|
||||
|
||||
@Inject
|
||||
internal lateinit var moshi: Moshi
|
||||
|
||||
private var sessionPtr: Long? = null
|
||||
|
||||
private var shouldReconnect: Boolean = false
|
||||
|
||||
private val activeTunnel: Tunnel?
|
||||
get() = tunnelRepository.get()
|
||||
|
||||
@@ -129,9 +137,9 @@ class TunnelService : VpnService() {
|
||||
}
|
||||
|
||||
override fun onDisconnect(error: String?): Boolean {
|
||||
Log.d(TAG, "onDisconnect $error")
|
||||
|
||||
onTunnelStateUpdate(Tunnel.State.Down)
|
||||
onSessionDisconnected(
|
||||
error = error?.takeUnless { it == "null" },
|
||||
)
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -169,11 +177,14 @@ class TunnelService : VpnService() {
|
||||
try {
|
||||
val config = getConfigUseCase.sync()
|
||||
|
||||
Log.d("Connlib", "accountId: ${config.accountId}")
|
||||
Log.d("Connlib", "token: ${config.token}")
|
||||
Log.d("Connlib", "connect(): accountId: ${config.accountId}")
|
||||
if (tunnelRepository.getState() == Tunnel.State.Up) {
|
||||
shouldReconnect = true
|
||||
disconnect()
|
||||
} else if (config.accountId != null && config.token != null) {
|
||||
onTunnelStateUpdate(Tunnel.State.Connecting)
|
||||
updateStatusNotification("Status: Connecting...")
|
||||
|
||||
if (config.accountId != null && config.token != null) {
|
||||
Log.d("Connlib", "Attempting to establish TunnelSession...")
|
||||
sessionPtr =
|
||||
TunnelSession.connect(
|
||||
controlPlaneUrl = BuildConfig.CONTROL_PLANE_URL,
|
||||
@@ -183,33 +194,40 @@ class TunnelService : VpnService() {
|
||||
logFilter = BuildConfig.CONNLIB_LOG_FILTER_STRING,
|
||||
callback = callback,
|
||||
)
|
||||
Log.d(TAG, "connlib session started! sessionPtr: $sessionPtr")
|
||||
|
||||
onTunnelStateUpdate(Tunnel.State.Connecting)
|
||||
|
||||
updateStatusNotification("Status: Connecting...")
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, exception.message.toString())
|
||||
Log.e(TAG, "connect(): " + exception.message.toString())
|
||||
}
|
||||
}
|
||||
|
||||
private fun disconnect() {
|
||||
Log.d(TAG, "Attempting to disconnect session")
|
||||
Log.d(TAG, "disconnect(): Attempting to disconnect session")
|
||||
try {
|
||||
sessionPtr?.let {
|
||||
Log.d(TAG, "calling TunnelSession.disconnect")
|
||||
TunnelSession.disconnect(it)
|
||||
}
|
||||
} ?: onSessionDisconnected(null)
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, exception.message.toString())
|
||||
}
|
||||
stopForeground(STOP_FOREGROUND_REMOVE)
|
||||
}
|
||||
|
||||
private fun onSessionDisconnected(error: String?) {
|
||||
sessionPtr = null
|
||||
onTunnelStateUpdate(Tunnel.State.Down)
|
||||
|
||||
if (shouldReconnect && error == null) {
|
||||
shouldReconnect = false
|
||||
connect()
|
||||
} else {
|
||||
tunnelRepository.clearAll()
|
||||
preferenceRepository.clearToken()
|
||||
onTunnelStateUpdate(Tunnel.State.Closed)
|
||||
stopForeground(STOP_FOREGROUND_REMOVE)
|
||||
}
|
||||
}
|
||||
|
||||
private fun deviceId(): String {
|
||||
val deviceId = FirebaseInstallations.getInstance().id
|
||||
|
||||
Log.d(TAG, "Device ID: $deviceId")
|
||||
|
||||
return deviceId.toString()
|
||||
@@ -294,5 +312,16 @@ class TunnelService : VpnService() {
|
||||
private const val TAG: String = "TunnelService"
|
||||
private const val SESSION_NAME: String = "Firezone Connection"
|
||||
private const val DEFAULT_MTU: Int = 1280
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
fun isRunning(context: Context): Boolean {
|
||||
val manager = context.getSystemService(ACTIVITY_SERVICE) as ActivityManager
|
||||
for (service in manager.getRunningServices(Int.MAX_VALUE)) {
|
||||
if (TunnelService::class.java.name == service.service.className) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ class TunnelRepositoryImpl
|
||||
|
||||
override fun getState(): Tunnel.State {
|
||||
val json = sharedPreferences.getString(STATE_KEY, null)
|
||||
return json?.let { Tunnel.State.valueOf(it) } ?: Tunnel.State.Down
|
||||
return json?.let { Tunnel.State.valueOf(it) } ?: Tunnel.State.Closed
|
||||
}
|
||||
|
||||
override fun setResources(resources: List<Resource>) {
|
||||
|
||||
@@ -14,8 +14,9 @@ data class Tunnel(
|
||||
val resources: List<Resource> = emptyList(),
|
||||
) : Parcelable {
|
||||
enum class State {
|
||||
Up,
|
||||
Connecting,
|
||||
Up,
|
||||
Down,
|
||||
Closed,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
android:id="@+id/btSignOut"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/sign_out_activity_button_text"
|
||||
android:text="@string/sign_out"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
@@ -47,7 +47,7 @@
|
||||
android:id="@+id/etInput"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/settings_fragment_input_hint"
|
||||
android:hint="@string/account_id"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="text" />
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:enabled="false"
|
||||
android:text="@string/settings_fragment_button_text"
|
||||
android:text="@string/save"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/spacing_small"
|
||||
android:text="@string/sign_in_fragment_sign_status_text"
|
||||
android:text="@string/signed_out"
|
||||
app:layout_constraintBottom_toTopOf="@+id/btSignIn"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
@@ -49,7 +49,7 @@
|
||||
android:id="@+id/btSignIn"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/sign_in_fragment_button_text"
|
||||
android:text="@string/sign_in"
|
||||
app:layout_constraintBottom_toTopOf="@+id/btSettings"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
@@ -58,7 +58,7 @@
|
||||
android:id="@+id/btSettings"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/sign_in_settings_button_text"
|
||||
android:text="@string/settings"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
@@ -8,85 +8,22 @@
|
||||
<fragment
|
||||
android:id="@+id/splashFragment"
|
||||
android:name="dev.firezone.android.features.splash.ui.SplashFragment"
|
||||
tools:layout="@layout/fragment_splash">
|
||||
|
||||
<action
|
||||
android:id="@+id/navigateToSettingsFragment"
|
||||
app:destination="@id/settingsFragment"
|
||||
app:enterAnim="@anim/fade_in"
|
||||
app:exitAnim="@anim/fade_out"
|
||||
app:popEnterAnim="@anim/fade_in"
|
||||
app:popExitAnim="@anim/fade_out" />
|
||||
|
||||
<action
|
||||
android:id="@+id/navigateToSignInFragment"
|
||||
app:destination="@id/signInFragment"
|
||||
app:enterAnim="@anim/fade_in"
|
||||
app:exitAnim="@anim/fade_out"
|
||||
app:popEnterAnim="@anim/fade_in"
|
||||
app:popExitAnim="@anim/fade_out" />
|
||||
|
||||
<action
|
||||
android:id="@+id/navigateToSessionFragment"
|
||||
app:destination="@id/sessionFragment"
|
||||
app:enterAnim="@anim/fade_in"
|
||||
app:exitAnim="@anim/fade_out"
|
||||
app:popEnterAnim="@anim/fade_in"
|
||||
app:popExitAnim="@anim/fade_out" />
|
||||
|
||||
</fragment>
|
||||
tools:layout="@layout/fragment_splash" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/settingsFragment"
|
||||
android:name="dev.firezone.android.features.settings.ui.SettingsFragment"
|
||||
tools:layout="@layout/fragment_settings">
|
||||
|
||||
<action
|
||||
android:id="@+id/navigateToSignInFragment"
|
||||
app:destination="@id/signInFragment"
|
||||
app:enterAnim="@anim/fade_in"
|
||||
app:exitAnim="@anim/fade_out"
|
||||
app:popEnterAnim="@anim/fade_in"
|
||||
app:popExitAnim="@anim/fade_out" />
|
||||
</fragment>
|
||||
tools:layout="@layout/fragment_settings" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/signInFragment"
|
||||
android:name="dev.firezone.android.features.signin.ui.SignInFragment"
|
||||
tools:layout="@layout/fragment_sign_in">
|
||||
tools:layout="@layout/fragment_sign_in" />
|
||||
|
||||
<action
|
||||
android:id="@+id/navigateToSessionFragment"
|
||||
app:destination="@id/sessionFragment"
|
||||
app:enterAnim="@anim/fade_in"
|
||||
app:exitAnim="@anim/fade_out"
|
||||
app:popEnterAnim="@anim/fade_in"
|
||||
app:popExitAnim="@anim/fade_out" />
|
||||
|
||||
<action
|
||||
android:id="@+id/navigateToSettingsFragment"
|
||||
app:destination="@id/settingsFragment"
|
||||
app:enterAnim="@anim/fade_in"
|
||||
app:exitAnim="@anim/fade_out"
|
||||
app:popEnterAnim="@anim/fade_in"
|
||||
app:popExitAnim="@anim/fade_out" />
|
||||
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/sessionFragment"
|
||||
android:name="dev.firezone.android.features.session.ui.SessionFragment"
|
||||
tools:layout="@layout/fragment_session">
|
||||
|
||||
<action
|
||||
android:id="@+id/navigateToSignInFragment"
|
||||
app:destination="@id/signInFragment"
|
||||
app:enterAnim="@anim/fade_in"
|
||||
app:exitAnim="@anim/fade_out"
|
||||
app:popEnterAnim="@anim/fade_in"
|
||||
app:popExitAnim="@anim/fade_out" />
|
||||
|
||||
</fragment>
|
||||
<activity
|
||||
android:id="@+id/sessionActivity"
|
||||
android:name="dev.firezone.android.features.session.ui.SessionActivity"
|
||||
tools:layout="@layout/activity_session" />
|
||||
|
||||
<activity
|
||||
android:id="@+id/vpnPermissionActivity"
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
<resources>
|
||||
<string name="app_short_name">firezone</string>
|
||||
|
||||
<!-- Settings Fragment -->
|
||||
<string name="settings_fragment_header_title">Login URL</string>
|
||||
<string name="settings_fragment_input_hint">account-id</string>
|
||||
<string name="settings_fragment_button_text">Save</string>
|
||||
<!-- Settings -->
|
||||
<string name="account_id">account-id</string>
|
||||
<string name="save">Save</string>
|
||||
|
||||
<!-- Sign In Fragment -->
|
||||
<string name="sign_in_fragment_button_text">Sign In</string>
|
||||
<string name="sign_in_settings_button_text">Settings</string>
|
||||
<string name="sign_in_fragment_sign_status_text">Signed Out</string>
|
||||
<!-- Sign In -->
|
||||
<string name="sign_in">Sign In</string>
|
||||
<string name="settings">Settings</string>
|
||||
<string name="signed_out">Signed Out</string>
|
||||
|
||||
<!-- Sign Out Activity -->
|
||||
<!-- Sign Out -->
|
||||
<string name="resources">Resources</string>
|
||||
<string name="sign_out_activity_button_text">Sign Out</string>
|
||||
<string name="sign_out">Sign Out</string>
|
||||
|
||||
<!-- Auth Activity -->
|
||||
<!-- Auth -->
|
||||
<string name="launching_auth_flow">Launching Auth Flow…</string>
|
||||
|
||||
<!-- Error Dialog -->
|
||||
|
||||
Reference in New Issue
Block a user