From 53646c1caf696e7d829b8e65fc77c9e47d923d11 Mon Sep 17 00:00:00 2001 From: Anton Litvinov Date: Wed, 24 Aug 2022 18:31:59 +0400 Subject: [PATCH 01/11] Add initial support of provider mode --- android/app/src/main/AndroidManifest.xml | 4 + .../java/updated/mysterium/vpn/di/Modules.kt | 4 + .../vpn/network/usecase/ConnectionUseCase.kt | 13 ++ .../mysterium/vpn/ui/menu/MenuActivity.kt | 8 + .../vpn/ui/provider/ProviderActivity.kt | 210 ++++++++++++++++++ .../vpn/ui/provider/ProviderViewModel.kt | 104 +++++++++ .../src/main/res/layout/activity_profile.xml | 3 +- .../src/main/res/layout/activity_provider.xml | 135 +++++++++++ android/app/src/main/res/values/strings.xml | 7 + 9 files changed, 486 insertions(+), 2 deletions(-) create mode 100644 android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderActivity.kt create mode 100644 android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderViewModel.kt create mode 100644 android/app/src/main/res/layout/activity_provider.xml diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 1c411448e..2df775a17 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -89,6 +89,10 @@ android:name="updated.mysterium.vpn.ui.settings.SettingsActivity" android:screenOrientation="portrait" /> + + diff --git a/android/app/src/main/java/updated/mysterium/vpn/di/Modules.kt b/android/app/src/main/java/updated/mysterium/vpn/di/Modules.kt index 42d82e5cb..598ff953c 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/di/Modules.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/di/Modules.kt @@ -31,6 +31,7 @@ import updated.mysterium.vpn.ui.onboarding.OnboardingViewModel import updated.mysterium.vpn.ui.prepare.top.up.PrepareTopUpViewModel import updated.mysterium.vpn.ui.private.key.PrivateKeyViewModel import updated.mysterium.vpn.ui.profile.ProfileViewModel +import updated.mysterium.vpn.ui.provider.ProviderViewModel import updated.mysterium.vpn.ui.report.issue.ReportIssueViewModel import updated.mysterium.vpn.ui.search.SearchViewModel import updated.mysterium.vpn.ui.settings.SettingsViewModel @@ -150,6 +151,9 @@ object Modules { viewModel { RegistrationViewModel(get()) } + viewModel { + ProviderViewModel(get()) + } } fun provideDatabase(context: Context) = Room.databaseBuilder( diff --git a/android/app/src/main/java/updated/mysterium/vpn/network/usecase/ConnectionUseCase.kt b/android/app/src/main/java/updated/mysterium/vpn/network/usecase/ConnectionUseCase.kt index f1a917cec..d87b7ea34 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/network/usecase/ConnectionUseCase.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/network/usecase/ConnectionUseCase.kt @@ -3,10 +3,12 @@ package updated.mysterium.vpn.network.usecase import mysterium.ConnectRequest import mysterium.GetIdentityRequest import mysterium.RegisterIdentityRequest +import okhttp3.internal.format import updated.mysterium.vpn.core.DeferredNode import updated.mysterium.vpn.core.NodeRepository import updated.mysterium.vpn.database.preferences.SharedPreferencesList import updated.mysterium.vpn.database.preferences.SharedPreferencesManager +import updated.mysterium.vpn.model.manual.connect.ConnectionState import updated.mysterium.vpn.model.statistics.Statistics import updated.mysterium.vpn.model.wallet.Identity @@ -82,4 +84,15 @@ class ConnectionUseCase( ) = nodeRepository.registerConnectionStatusChangeCallback(callback) suspend fun disconnect() = nodeRepository.disconnect() + + // + suspend fun getIsProviderActive(): Boolean { + var s = nodeRepository.status() + println (format(">>>>>>>>>>>> pro %s ", s.proposal!!.providerID)) + + if (s.state == ConnectionState.CONNECTED && s.proposal!!.providerID != "") { + return true + } + return false + } } diff --git a/android/app/src/main/java/updated/mysterium/vpn/ui/menu/MenuActivity.kt b/android/app/src/main/java/updated/mysterium/vpn/ui/menu/MenuActivity.kt index f7fd31c2c..7610a68cb 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/ui/menu/MenuActivity.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/ui/menu/MenuActivity.kt @@ -22,6 +22,7 @@ import updated.mysterium.vpn.ui.monitoring.MonitoringActivity import updated.mysterium.vpn.ui.profile.ProfileActivity import updated.mysterium.vpn.ui.report.issue.ReportIssueActivity import updated.mysterium.vpn.ui.settings.SettingsActivity +import updated.mysterium.vpn.ui.provider.ProviderActivity import updated.mysterium.vpn.ui.terms.TermsOfUseActivity import updated.mysterium.vpn.ui.wallet.WalletActivity @@ -50,6 +51,10 @@ class MenuActivity : BaseActivity() { iconResId = R.drawable.menu_icon_settings, titleResId = R.string.menu_list_item_settings, ), + MenuItem( + iconResId = R.drawable.menu_icon_settings, + titleResId = R.string.menu_list_item_provider, + ), MenuItem( iconResId = R.drawable.menu_icon_referral_deactivated, titleResId = R.string.menu_item_referral_title, @@ -185,6 +190,9 @@ class MenuActivity : BaseActivity() { startActivity(Intent(this, SettingsActivity::class.java)) } 5 -> menuItem.onItemClickListener = { + startActivity(Intent(this, ProviderActivity::class.java)) + } + 6 -> menuItem.onItemClickListener = { // TODO("Implement navigation to Referral") } } diff --git a/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderActivity.kt b/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderActivity.kt new file mode 100644 index 000000000..ccf300ba6 --- /dev/null +++ b/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderActivity.kt @@ -0,0 +1,210 @@ +package updated.mysterium.vpn.ui.provider + +import android.os.Bundle +import android.view.View +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import network.mysterium.vpn.databinding.ActivityProviderBinding +import okhttp3.internal.wait +import org.koin.android.ext.android.inject +import updated.mysterium.vpn.App +import updated.mysterium.vpn.ui.base.BaseActivity + +class ProviderActivity : BaseActivity() { + + private companion object { + const val TAG = "ProviderActivity" + } + + private lateinit var binding: ActivityProviderBinding + private val viewModel: ProviderViewModel by inject() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityProviderBinding.inflate(layoutInflater) + setContentView(binding.root) + configure() + bindsAction() + + + viewModel.init( + deferredMysteriumCoreService = App.getInstance(this).deferredMysteriumCoreService, + ) + } + + override fun showConnectionHint() { + binding.connectionHint.visibility = View.VISIBLE + baseViewModel.hintShown() + } + + private fun configure() { + initToolbar(binding.manualConnectToolbar) + + + GlobalScope.launch { + binding.darkModeSwitch.isChecked = viewModel.getIsProviderActive_() + } + + +// setUpDnsSpinner() +// setUpResidentCountryList() +// checkPreviousDnsOption() +// checkPreviousResidentCountry() +// checkCurrentLightMode() +// checkNatCompatibility() + } + + private fun bindsAction() { + binding.manualConnectToolbar.onConnectClickListener { + navigateToConnectionIfConnectedOrHome() + } + binding.manualConnectToolbar.onLeftButtonClicked { + finish() + } + +// binding.selectedCountryFrame.setOnClickListener { +// changeCountryListVisibility() +// } + + binding.darkModeSwitch.setOnCheckedChangeListener { _, isChecked -> +// println(viewModel) + + viewModel.toggleProvider(isChecked) + +// if (isChecked) { +// applyDarkTheme() +// } else { +// applyLightTheme() +// } + } +// binding.isNatAvailableCheckBox.setOnCheckedChangeListener { _, isChecked -> +// viewModel.setNatOption(isChecked) +// } +// binding.natHelperFrameButton.setOnClickListener { +// showNatCompatibilityPopUpWindow() +// } + } + +// private fun checkCurrentLightMode() { +// binding.darkModeSwitch.isChecked = isDarkThemeOn() +// } + +// private fun checkNatCompatibility() { +// binding.isNatAvailableCheckBox.isChecked = viewModel.isNatCompatibilityAvailable() +// } + +// private fun applyDarkTheme() { +// AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) +// delegate.applyDayNight() +// } +// +// private fun applyLightTheme() { +// AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) +// delegate.applyDayNight() +// } + +// private fun setUpDnsSpinner() { +// val languagesList = DNS_OPTIONS.map { getString(it.translatableValueResId) } +// val spinnerAdapter = SpinnerArrayAdapter( +// this, +// R.layout.item_spinner_dns, +// languagesList +// ) +// binding.dnsSpinner.apply { +// binding.dnsSpinnerFrame.setOnClickListener { +// performClick() +// } +// adapter = spinnerAdapter +// onItemSelected { +// spinnerAdapter.selectedPosition = it +// viewModel.saveDnsOption(DNS_OPTIONS[it].backendValue) +// } +// } +// } + +// private fun checkPreviousDnsOption() { +// viewModel.getSavedDnsOption()?.let { selectedValue -> +// val dnsOption = DNS_OPTIONS.find { it.backendValue == selectedValue } +// binding.dnsSpinner.setSelection(DNS_OPTIONS.indexOf(dnsOption)) +// } +// } + +// private fun checkPreviousResidentCountry() { +// viewModel.getResidentCountry().observe(this) { result -> +// val countriesList = CountriesUtil.getAllResidentCountries() +// result.onSuccess { residentDigitCode -> +// val residentCountry = countriesList.find { it.code == residentDigitCode } +// binding.selectedCountry.text = residentCountry?.fullName +// ?: countriesList.first().fullName +// } +// result.onFailure { +// binding.selectedCountry.text = countriesList.first().fullName +// Log.e(TAG, it.localizedMessage ?: it.toString()) +// } +// } +// } + +// private fun setUpResidentCountryList() { +// val countriesList = CountriesUtil.getAllResidentCountries() +// val countriesListName = countriesList.map { it.fullName } +// binding.selectedCountry.text = countriesListName.first() +// ResidentCountryAdapter().apply { +// addAll(countriesListName) +// onCountrySelected = { position -> +// binding.selectedCountry.text = countriesListName[position] +// viewModel.saveResidentCountry(countriesList[position].code) +// binding.residentCountryList.visibility = View.INVISIBLE +// } +// binding.residentCountryList.adapter = this +// } +// } + +// private fun changeCountryListVisibility() { +// if (binding.residentCountryList.visibility == View.INVISIBLE) { +// calculateSpinnerSize() +// binding.residentCountryList.visibility = View.VISIBLE +// } else { +// binding.residentCountryList.visibility = View.INVISIBLE +// } +// } + +// private fun calculateSpinnerSize() { +// val size = Point() +// windowManager.defaultDisplay.getSize(size) // get screen size +// val location = IntArray(2) +// binding.residentCountryList.getLocationOnScreen(location) // get view coordinates +// val popUpHeight = size.y - location[1] // distance from view to screen bottom +// val margin = TypedValue.applyDimension( +// TypedValue.COMPLEX_UNIT_DIP, +// resources.getDimension(R.dimen.margin_padding_size_large), +// resources.displayMetrics +// ).toInt() +// if (popUpHeight > margin) { +// val lp = binding.residentCountryList.layoutParams +// lp.height = popUpHeight - margin +// binding.residentCountryList.layoutParams = lp +// } +// } + +// private fun showNatCompatibilityPopUpWindow() { +// val bindingPopUpView = ViewItemNatCompatibilityDescriptionBinding.inflate( +// LayoutInflater.from(this) +// ) +// +// FlowablePopupWindow( +// contentView = bindingPopUpView.root, +// width = DimenUtils.dpToPx(POPUP_WINDOW_WIDTH_DP) +// ).apply { +// gravity = Gravity.TOP +// xOffset = DimenUtils.dpToPx(POPUP_WINDOW_END_OFFSET_DP) +// yOffset = 5 //getPopUpWindowVerticalOffset() +// }.show() +// } + +// private fun getPopUpWindowVerticalOffset(): Int { +// val baseViewRectangle = binding.root.calculateRectOnScreen() +// val hintButtonViewRectangle = binding.natHelperFrameButton.calculateRectOnScreen() +// val distance = abs(baseViewRectangle.top - hintButtonViewRectangle.bottom).toInt() +// return distance + DimenUtils.dpToPx(POPUP_WINDOW_TOP_OFFSET_DP) +// } +} diff --git a/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderViewModel.kt b/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderViewModel.kt new file mode 100644 index 000000000..7b7759d95 --- /dev/null +++ b/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderViewModel.kt @@ -0,0 +1,104 @@ +package updated.mysterium.vpn.ui.provider + +import android.util.Log +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.* +import okhttp3.internal.wait +import updated.mysterium.vpn.core.DeferredNode +import updated.mysterium.vpn.core.MysteriumCoreService +import updated.mysterium.vpn.network.provider.usecase.UseCaseProvider + +class ProviderViewModel(useCaseProvider: UseCaseProvider) : ViewModel() { + + private companion object { + const val TAG = "ProviderViewModel" + } + + private val settingsUseCase = useCaseProvider.settings() + private val providerUseCase = useCaseProvider.connection() + private var deferredNode = DeferredNode() + private var coreService: MysteriumCoreService? = null + val handler = CoroutineExceptionHandler { _, exception -> + Log.i(TAG, exception.localizedMessage ?: exception.toString()) +// if (!isConnectionStopped && _connectionStatus.value?.state != ConnectionState.CONNECTED) { +// _connectionException.postValue(exception as Exception) +// } +// isConnectionStopped = false + } + + fun init( + deferredMysteriumCoreService: CompletableDeferred, + ) { + viewModelScope.launch(handler) { +// appNotificationManager = notificationManager + coreService = deferredMysteriumCoreService.await() +// startDeferredNode() +// connect(connectionType, countryCode, proposal, rate) + } + } + + fun toggleProvider(isCheccked: Boolean) { + Log.d(TAG, "isChecked >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>") + println(deferredNode.startedOrStarting()) + +// if (!deferredNode.startedOrStarting()) { + viewModelScope.launch(handler) { + coreService?.let { + + var a = getIsProviderActive_() + if (!a && isCheccked) { + + providerUseCase.disconnect() +// providerUseCase.connect() +// deferredNode.await().disconnect() +// deferredNode.wait() +// deferredNode.start(it) + + } + + + + } + } + +// } + //settingsUseCase.setUserDarkMode(isDark) + } + + fun saveDnsOption(dnsOption: String) { + //settingsUseCase.saveDns(dnsOption) + } + +// fun getSavedDnsOption() = settingsUseCase.getSavedDns() +// +// fun saveResidentCountry(countryCode: String) { +// val handler = CoroutineExceptionHandler { _, exception -> +// Log.e(TAG, exception.localizedMessage ?: exception.toString()) +// } +// viewModelScope.launch(handler) { +// val identityAddress = connectionUseCase.getIdentityAddress() +// settingsUseCase.saveResidentCountry(identityAddress, countryCode) +// } +// } + +// fun getResidentCountry() = liveDataResult { +// settingsUseCase.getResidentCountry() +// } +// +// fun changeLightMode(isDark: Boolean) { +// settingsUseCase.setUserDarkMode(isDark) +// } + + fun setNatOption(isNatAvailable: Boolean) { + settingsUseCase.setNatCompatibility(isNatAvailable) + } + + fun isNatCompatibilityAvailable() = settingsUseCase.isNatAvailable() + + suspend fun getIsProviderActive_(): Boolean { + return providerUseCase.getIsProviderActive() + } + + +} diff --git a/android/app/src/main/res/layout/activity_profile.xml b/android/app/src/main/res/layout/activity_profile.xml index 8f8f38e02..115a11989 100644 --- a/android/app/src/main/res/layout/activity_profile.xml +++ b/android/app/src/main/res/layout/activity_profile.xml @@ -47,8 +47,7 @@ + android:layout_height="wrap_content"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 79850651f..562d35f94 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -92,6 +92,8 @@ Top up your account Connection history Settings + Provider mode + Report an issue Get help Terms of Use @@ -197,6 +199,11 @@ Warning: It takes a few minutes to process payments after topping up You can\'t make a payment if the account balance is more than 50 MYST + + Server + Myst provider + Enable + Settings Identity is your Mysterium internal user ID. Never send ether or any kind of ERC20 tokens there. From 6df34eedef6197dfb1e698ae2cc559310544af0a Mon Sep 17 00:00:00 2001 From: Anton Litvinov Date: Wed, 16 Nov 2022 20:39:02 +0400 Subject: [PATCH 02/11] Stop consumer when provider starts --- .../mysterium/vpn/core/DeferredNode.kt | 8 + .../vpn/core/MysteriumAndroidCoreService.kt | 51 ++++++ .../vpn/core/MysteriumCoreService.kt | 3 + .../vpn/network/usecase/ConnectionUseCase.kt | 11 -- .../vpn/ui/connection/ConnectionViewModel.kt | 2 +- .../vpn/ui/provider/ProviderActivity.kt | 160 +----------------- .../vpn/ui/provider/ProviderViewModel.kt | 82 +++------ .../vpn/ui/splash/SplashViewModel.kt | 2 +- .../src/main/res/layout/activity_provider.xml | 2 +- fastlane/README.md | 55 +++--- 10 files changed, 123 insertions(+), 253 deletions(-) diff --git a/android/app/src/main/java/updated/mysterium/vpn/core/DeferredNode.kt b/android/app/src/main/java/updated/mysterium/vpn/core/DeferredNode.kt index 6cd30fafb..8b83dee7a 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/core/DeferredNode.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/core/DeferredNode.kt @@ -22,10 +22,14 @@ class DeferredNode { suspend fun start( service: MysteriumCoreService, + isProvider: Boolean, done: ((err: Exception?) -> Unit)? = null ) { + println("MYDBG > DeferredNode.start: $isProvider") + if (!lock.tryAcquire()) { Log.i(TAG, "Node is already started or starting, skipping") + } else { val handler = CoroutineExceptionHandler { _, exception -> Log.e(TAG, exception.localizedMessage ?: exception.toString()) @@ -33,6 +37,10 @@ class DeferredNode { } var node: MobileNode? = null val startJob = CoroutineScope(Dispatchers.IO + handler).launch { + if (isProvider) { + node = service.startProviderNode() + return@launch + } node = service.startNode() } startJob.invokeOnCompletion { diff --git a/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumAndroidCoreService.kt b/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumAndroidCoreService.kt index fa2c399e4..8a8207f15 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumAndroidCoreService.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumAndroidCoreService.kt @@ -75,8 +75,14 @@ class MysteriumAndroidCoreService : VpnService(), KoinComponent { private var currentState = ConnectionState.NOTCONNECTED private var vpnTimeSpent: Float? = null // time spent for last session in minutes private var secondsBetweenAnalyticEvent = 0 + private var isProviderActive = false + init { + println("MYDBG > MysteriumAndroidCoreService") + } override fun onDestroy() { + println("MYDBG > onDestroy") + stopMobileNode() super.onDestroy() } @@ -89,7 +95,42 @@ class MysteriumAndroidCoreService : VpnService(), KoinComponent { return MysteriumCoreServiceBridge() } + private fun startMobileProviderNode(filesPath: String): MobileNode { + println("MYDBG > startMobileProviderNode $filesPath") + + isProviderActive = true + mobileNode?.let { + val i = it.isProvider() + if (i) { + mobileNode = null + } else { + // stop consumer + stopMobileNode() + mobileNode = null + } + } + + println("MYDBG > startMobileProviderNode !11") + if (mobileNode == null) { + try { + mobileNode = Mysterium.newProviderNode(filesPath) + } catch (e: Exception) { + println(e) + } + } + + mobileNode?.let { + it.overrideWireguardConnection(WireguardAndroidTunnelSetup(this@MysteriumAndroidCoreService)) + it.startProvider() + + println("MYDBG > startMobileProviderNode !2") + return it + } + return mobileNode?: MobileNode() + } + private fun startMobileNode(filesPath: String): MobileNode { + println("MYDBG > startMobileNode $filesPath") mobileNode?.let { return it } @@ -99,6 +140,7 @@ class MysteriumAndroidCoreService : VpnService(), KoinComponent { } private fun stopMobileNode() { + println("MYDBG > stopMobileNode") val node = mobileNode if (node == null) { Log.w(TAG, "Trying to stop node when instance is not set") @@ -270,6 +312,15 @@ class MysteriumAndroidCoreService : VpnService(), KoinComponent { } inner class MysteriumCoreServiceBridge : Binder(), MysteriumCoreService { + override suspend fun startProviderNode(): MobileNode { + return startMobileProviderNode(filesDir.canonicalPath) + } + override fun setProviderActive(provider: Boolean) { + isProviderActive = provider + } + override fun isProviderActive(): Boolean { + return isProviderActive + } override fun getDeferredNode() = deferredNode diff --git a/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumCoreService.kt b/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumCoreService.kt index 4f1e98ed3..cd804d422 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumCoreService.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumCoreService.kt @@ -26,6 +26,9 @@ import updated.mysterium.vpn.notification.NotificationFactory interface MysteriumCoreService : IBinder { suspend fun startNode(): MobileNode + suspend fun startProviderNode(): MobileNode + fun isProviderActive(): Boolean + fun setProviderActive(provider: Boolean) fun stopNode() diff --git a/android/app/src/main/java/updated/mysterium/vpn/network/usecase/ConnectionUseCase.kt b/android/app/src/main/java/updated/mysterium/vpn/network/usecase/ConnectionUseCase.kt index d87b7ea34..597906bf4 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/network/usecase/ConnectionUseCase.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/network/usecase/ConnectionUseCase.kt @@ -84,15 +84,4 @@ class ConnectionUseCase( ) = nodeRepository.registerConnectionStatusChangeCallback(callback) suspend fun disconnect() = nodeRepository.disconnect() - - // - suspend fun getIsProviderActive(): Boolean { - var s = nodeRepository.status() - println (format(">>>>>>>>>>>> pro %s ", s.proposal!!.providerID)) - - if (s.state == ConnectionState.CONNECTED && s.proposal!!.providerID != "") { - return true - } - return false - } } diff --git a/android/app/src/main/java/updated/mysterium/vpn/ui/connection/ConnectionViewModel.kt b/android/app/src/main/java/updated/mysterium/vpn/ui/connection/ConnectionViewModel.kt index e0d41c398..6d3a1332c 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/ui/connection/ConnectionViewModel.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/ui/connection/ConnectionViewModel.kt @@ -250,7 +250,7 @@ class ConnectionViewModel(useCaseProvider: UseCaseProvider) : ViewModel() { private suspend fun startDeferredNode() { if (!deferredNode.startedOrStarting()) { coreService?.let { - deferredNode.start(it) + deferredNode.start(it, false) } } connectionUseCase.initDeferredNode(deferredNode) diff --git a/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderActivity.kt b/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderActivity.kt index ccf300ba6..e69ba243b 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderActivity.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderActivity.kt @@ -5,7 +5,6 @@ import android.view.View import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import network.mysterium.vpn.databinding.ActivityProviderBinding -import okhttp3.internal.wait import org.koin.android.ext.android.inject import updated.mysterium.vpn.App import updated.mysterium.vpn.ui.base.BaseActivity @@ -23,13 +22,12 @@ class ProviderActivity : BaseActivity() { super.onCreate(savedInstanceState) binding = ActivityProviderBinding.inflate(layoutInflater) setContentView(binding.root) - configure() - bindsAction() - viewModel.init( deferredMysteriumCoreService = App.getInstance(this).deferredMysteriumCoreService, ) + configure() + bindsAction() } override fun showConnectionHint() { @@ -40,18 +38,9 @@ class ProviderActivity : BaseActivity() { private fun configure() { initToolbar(binding.manualConnectToolbar) - GlobalScope.launch { - binding.darkModeSwitch.isChecked = viewModel.getIsProviderActive_() + binding.providerModeSwitch.isChecked = viewModel.getIsProvider() } - - -// setUpDnsSpinner() -// setUpResidentCountryList() -// checkPreviousDnsOption() -// checkPreviousResidentCountry() -// checkCurrentLightMode() -// checkNatCompatibility() } private fun bindsAction() { @@ -61,150 +50,9 @@ class ProviderActivity : BaseActivity() { binding.manualConnectToolbar.onLeftButtonClicked { finish() } - -// binding.selectedCountryFrame.setOnClickListener { -// changeCountryListVisibility() -// } - - binding.darkModeSwitch.setOnCheckedChangeListener { _, isChecked -> -// println(viewModel) - + binding.providerModeSwitch.setOnCheckedChangeListener { _, isChecked -> viewModel.toggleProvider(isChecked) - -// if (isChecked) { -// applyDarkTheme() -// } else { -// applyLightTheme() -// } } -// binding.isNatAvailableCheckBox.setOnCheckedChangeListener { _, isChecked -> -// viewModel.setNatOption(isChecked) -// } -// binding.natHelperFrameButton.setOnClickListener { -// showNatCompatibilityPopUpWindow() -// } } -// private fun checkCurrentLightMode() { -// binding.darkModeSwitch.isChecked = isDarkThemeOn() -// } - -// private fun checkNatCompatibility() { -// binding.isNatAvailableCheckBox.isChecked = viewModel.isNatCompatibilityAvailable() -// } - -// private fun applyDarkTheme() { -// AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) -// delegate.applyDayNight() -// } -// -// private fun applyLightTheme() { -// AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) -// delegate.applyDayNight() -// } - -// private fun setUpDnsSpinner() { -// val languagesList = DNS_OPTIONS.map { getString(it.translatableValueResId) } -// val spinnerAdapter = SpinnerArrayAdapter( -// this, -// R.layout.item_spinner_dns, -// languagesList -// ) -// binding.dnsSpinner.apply { -// binding.dnsSpinnerFrame.setOnClickListener { -// performClick() -// } -// adapter = spinnerAdapter -// onItemSelected { -// spinnerAdapter.selectedPosition = it -// viewModel.saveDnsOption(DNS_OPTIONS[it].backendValue) -// } -// } -// } - -// private fun checkPreviousDnsOption() { -// viewModel.getSavedDnsOption()?.let { selectedValue -> -// val dnsOption = DNS_OPTIONS.find { it.backendValue == selectedValue } -// binding.dnsSpinner.setSelection(DNS_OPTIONS.indexOf(dnsOption)) -// } -// } - -// private fun checkPreviousResidentCountry() { -// viewModel.getResidentCountry().observe(this) { result -> -// val countriesList = CountriesUtil.getAllResidentCountries() -// result.onSuccess { residentDigitCode -> -// val residentCountry = countriesList.find { it.code == residentDigitCode } -// binding.selectedCountry.text = residentCountry?.fullName -// ?: countriesList.first().fullName -// } -// result.onFailure { -// binding.selectedCountry.text = countriesList.first().fullName -// Log.e(TAG, it.localizedMessage ?: it.toString()) -// } -// } -// } - -// private fun setUpResidentCountryList() { -// val countriesList = CountriesUtil.getAllResidentCountries() -// val countriesListName = countriesList.map { it.fullName } -// binding.selectedCountry.text = countriesListName.first() -// ResidentCountryAdapter().apply { -// addAll(countriesListName) -// onCountrySelected = { position -> -// binding.selectedCountry.text = countriesListName[position] -// viewModel.saveResidentCountry(countriesList[position].code) -// binding.residentCountryList.visibility = View.INVISIBLE -// } -// binding.residentCountryList.adapter = this -// } -// } - -// private fun changeCountryListVisibility() { -// if (binding.residentCountryList.visibility == View.INVISIBLE) { -// calculateSpinnerSize() -// binding.residentCountryList.visibility = View.VISIBLE -// } else { -// binding.residentCountryList.visibility = View.INVISIBLE -// } -// } - -// private fun calculateSpinnerSize() { -// val size = Point() -// windowManager.defaultDisplay.getSize(size) // get screen size -// val location = IntArray(2) -// binding.residentCountryList.getLocationOnScreen(location) // get view coordinates -// val popUpHeight = size.y - location[1] // distance from view to screen bottom -// val margin = TypedValue.applyDimension( -// TypedValue.COMPLEX_UNIT_DIP, -// resources.getDimension(R.dimen.margin_padding_size_large), -// resources.displayMetrics -// ).toInt() -// if (popUpHeight > margin) { -// val lp = binding.residentCountryList.layoutParams -// lp.height = popUpHeight - margin -// binding.residentCountryList.layoutParams = lp -// } -// } - -// private fun showNatCompatibilityPopUpWindow() { -// val bindingPopUpView = ViewItemNatCompatibilityDescriptionBinding.inflate( -// LayoutInflater.from(this) -// ) -// -// FlowablePopupWindow( -// contentView = bindingPopUpView.root, -// width = DimenUtils.dpToPx(POPUP_WINDOW_WIDTH_DP) -// ).apply { -// gravity = Gravity.TOP -// xOffset = DimenUtils.dpToPx(POPUP_WINDOW_END_OFFSET_DP) -// yOffset = 5 //getPopUpWindowVerticalOffset() -// }.show() -// } - -// private fun getPopUpWindowVerticalOffset(): Int { -// val baseViewRectangle = binding.root.calculateRectOnScreen() -// val hintButtonViewRectangle = binding.natHelperFrameButton.calculateRectOnScreen() -// val distance = abs(baseViewRectangle.top - hintButtonViewRectangle.bottom).toInt() -// return distance + DimenUtils.dpToPx(POPUP_WINDOW_TOP_OFFSET_DP) -// } } diff --git a/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderViewModel.kt b/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderViewModel.kt index 7b7759d95..8f8d59e0b 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderViewModel.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderViewModel.kt @@ -4,7 +4,6 @@ import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.* -import okhttp3.internal.wait import updated.mysterium.vpn.core.DeferredNode import updated.mysterium.vpn.core.MysteriumCoreService import updated.mysterium.vpn.network.provider.usecase.UseCaseProvider @@ -15,90 +14,47 @@ class ProviderViewModel(useCaseProvider: UseCaseProvider) : ViewModel() { const val TAG = "ProviderViewModel" } - private val settingsUseCase = useCaseProvider.settings() - private val providerUseCase = useCaseProvider.connection() private var deferredNode = DeferredNode() private var coreService: MysteriumCoreService? = null val handler = CoroutineExceptionHandler { _, exception -> Log.i(TAG, exception.localizedMessage ?: exception.toString()) -// if (!isConnectionStopped && _connectionStatus.value?.state != ConnectionState.CONNECTED) { -// _connectionException.postValue(exception as Exception) -// } -// isConnectionStopped = false } fun init( deferredMysteriumCoreService: CompletableDeferred, ) { + println("ProviderViewModel > init") viewModelScope.launch(handler) { -// appNotificationManager = notificationManager coreService = deferredMysteriumCoreService.await() -// startDeferredNode() -// connect(connectionType, countryCode, proposal, rate) } } - fun toggleProvider(isCheccked: Boolean) { - Log.d(TAG, "isChecked >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>") - println(deferredNode.startedOrStarting()) + fun toggleProvider(isChecked: Boolean) { -// if (!deferredNode.startedOrStarting()) { - viewModelScope.launch(handler) { - coreService?.let { - - var a = getIsProviderActive_() - if (!a && isCheccked) { - - providerUseCase.disconnect() -// providerUseCase.connect() -// deferredNode.await().disconnect() -// deferredNode.wait() -// deferredNode.start(it) - - } + viewModelScope.launch(handler) { + coreService?.let { + if (isChecked) { + println ("MYDBG >>>>>>>>>>>> connect ! ") + it.setProviderActive(true) + deferredNode.start(it, true) + } else { + println ("MYDBG >>>>>>>>>>>> disconnect ! ") + // disconnect + it.stopNode() + it.setProviderActive(false) } } - -// } - //settingsUseCase.setUserDarkMode(isDark) - } - - fun saveDnsOption(dnsOption: String) { - //settingsUseCase.saveDns(dnsOption) - } - -// fun getSavedDnsOption() = settingsUseCase.getSavedDns() -// -// fun saveResidentCountry(countryCode: String) { -// val handler = CoroutineExceptionHandler { _, exception -> -// Log.e(TAG, exception.localizedMessage ?: exception.toString()) -// } -// viewModelScope.launch(handler) { -// val identityAddress = connectionUseCase.getIdentityAddress() -// settingsUseCase.saveResidentCountry(identityAddress, countryCode) -// } -// } - -// fun getResidentCountry() = liveDataResult { -// settingsUseCase.getResidentCountry() -// } -// -// fun changeLightMode(isDark: Boolean) { -// settingsUseCase.setUserDarkMode(isDark) -// } - - fun setNatOption(isNatAvailable: Boolean) { - settingsUseCase.setNatCompatibility(isNatAvailable) + } } - fun isNatCompatibilityAvailable() = settingsUseCase.isNatAvailable() - - suspend fun getIsProviderActive_(): Boolean { - return providerUseCase.getIsProviderActive() + suspend fun getIsProvider(): Boolean { + coreService?.let { + return it.isProviderActive() + } + return false } - } diff --git a/android/app/src/main/java/updated/mysterium/vpn/ui/splash/SplashViewModel.kt b/android/app/src/main/java/updated/mysterium/vpn/ui/splash/SplashViewModel.kt index 634d9d1db..66f2f0a07 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/ui/splash/SplashViewModel.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/ui/splash/SplashViewModel.kt @@ -67,7 +67,7 @@ class SplashViewModel( } } else { service?.let { - deferredNode.start(it) { exception -> + deferredNode.start(it, false) { exception -> if (exception != null) { _nodeStartingError.postValue(exception) } else { diff --git a/android/app/src/main/res/layout/activity_provider.xml b/android/app/src/main/res/layout/activity_provider.xml index d0bb64dd1..7cc4455f0 100644 --- a/android/app/src/main/res/layout/activity_provider.xml +++ b/android/app/src/main/res/layout/activity_provider.xml @@ -117,7 +117,7 @@ android:textColor="@android:color/white" /> Date: Wed, 14 Dec 2022 05:06:12 +0400 Subject: [PATCH 03/11] Stop consumer when provider starts and vice versa --- .../mysterium/vpn/core/DeferredNode.kt | 8 +-- .../vpn/core/MysteriumAndroidCoreService.kt | 61 +++++++++---------- .../vpn/core/MysteriumCoreService.kt | 4 +- .../vpn/model/manual/connect/ProviderState.kt | 7 +++ .../vpn/ui/connection/ConnectionViewModel.kt | 5 +- .../vpn/ui/provider/ProviderActivity.kt | 6 +- .../vpn/ui/provider/ProviderViewModel.kt | 40 ++++++++---- .../vpn/ui/splash/SplashViewModel.kt | 2 +- 8 files changed, 74 insertions(+), 59 deletions(-) create mode 100644 android/app/src/main/java/updated/mysterium/vpn/model/manual/connect/ProviderState.kt diff --git a/android/app/src/main/java/updated/mysterium/vpn/core/DeferredNode.kt b/android/app/src/main/java/updated/mysterium/vpn/core/DeferredNode.kt index 8b83dee7a..c4349ed95 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/core/DeferredNode.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/core/DeferredNode.kt @@ -8,7 +8,6 @@ import mysterium.MobileNode // DeferredNode is a wrapper class which holds MobileNode instance promise. // This allows to load UI without waiting for node to start. class DeferredNode { - private companion object { const val TAG = "DeferredNode" } @@ -22,10 +21,9 @@ class DeferredNode { suspend fun start( service: MysteriumCoreService, - isProvider: Boolean, done: ((err: Exception?) -> Unit)? = null ) { - println("MYDBG > DeferredNode.start: $isProvider") + println("MYDBG > DeferredNode.start") if (!lock.tryAcquire()) { Log.i(TAG, "Node is already started or starting, skipping") @@ -37,10 +35,6 @@ class DeferredNode { } var node: MobileNode? = null val startJob = CoroutineScope(Dispatchers.IO + handler).launch { - if (isProvider) { - node = service.startProviderNode() - return@launch - } node = service.startNode() } startJob.invokeOnCompletion { diff --git a/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumAndroidCoreService.kt b/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumAndroidCoreService.kt index 8a8207f15..da8949e5f 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumAndroidCoreService.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumAndroidCoreService.kt @@ -25,10 +25,7 @@ import android.os.Binder import android.os.Bundle import android.os.IBinder import android.util.Log -import kotlinx.coroutines.CoroutineExceptionHandler -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch +import kotlinx.coroutines.* import mysterium.MobileNode import mysterium.Mysterium import network.mysterium.vpn.R @@ -95,38 +92,39 @@ class MysteriumAndroidCoreService : VpnService(), KoinComponent { return MysteriumCoreServiceBridge() } - private fun startMobileProviderNode(filesPath: String): MobileNode { - println("MYDBG > startMobileProviderNode $filesPath") - - isProviderActive = true + private fun startMobileProviderService(active: Boolean) { + println("MYDBG > startMobileProviderService") mobileNode?.let { - val i = it.isProvider() - if (i) { - mobileNode = null - } else { - // stop consumer - stopMobileNode() - mobileNode = null - } - } - - println("MYDBG > startMobileProviderNode !11") - if (mobileNode == null) { try { - mobileNode = Mysterium.newProviderNode(filesPath) + isProviderActive = active + if (active) { + it.startProvider() + } else { + it.stopProvider() + } } catch (e: Exception) { println(e) } } + } - mobileNode?.let { - it.overrideWireguardConnection(WireguardAndroidTunnelSetup(this@MysteriumAndroidCoreService)) - it.startProvider() + private fun innerStopConsumer() { + println("MYDBG > stopConsumer >") + var c = currentState == ConnectionState.CONNECTED || + currentState == ConnectionState.CONNECTING || + currentState == ConnectionState.ON_HOLD || + currentState == ConnectionState.IP_NOT_CHANGED - println("MYDBG > startMobileProviderNode !2") - return it + + GlobalScope.launch(Dispatchers.IO) { + if (c) { + connectionUseCase.disconnect() + + activeProposal = null + deferredNode = null + stopForeground(true) + } } - return mobileNode?: MobileNode() } private fun startMobileNode(filesPath: String): MobileNode { @@ -312,11 +310,12 @@ class MysteriumAndroidCoreService : VpnService(), KoinComponent { } inner class MysteriumCoreServiceBridge : Binder(), MysteriumCoreService { - override suspend fun startProviderNode(): MobileNode { - return startMobileProviderNode(filesDir.canonicalPath) + + override fun stopConsumer() { + innerStopConsumer() } - override fun setProviderActive(provider: Boolean) { - isProviderActive = provider + override fun startProvider(active: Boolean) { + startMobileProviderService(active) } override fun isProviderActive(): Boolean { return isProviderActive diff --git a/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumCoreService.kt b/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumCoreService.kt index cd804d422..4be88f539 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumCoreService.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumCoreService.kt @@ -26,9 +26,9 @@ import updated.mysterium.vpn.notification.NotificationFactory interface MysteriumCoreService : IBinder { suspend fun startNode(): MobileNode - suspend fun startProviderNode(): MobileNode fun isProviderActive(): Boolean - fun setProviderActive(provider: Boolean) + fun startProvider(provider: Boolean) + fun stopConsumer() fun stopNode() diff --git a/android/app/src/main/java/updated/mysterium/vpn/model/manual/connect/ProviderState.kt b/android/app/src/main/java/updated/mysterium/vpn/model/manual/connect/ProviderState.kt new file mode 100644 index 000000000..7aac16660 --- /dev/null +++ b/android/app/src/main/java/updated/mysterium/vpn/model/manual/connect/ProviderState.kt @@ -0,0 +1,7 @@ +package updated.mysterium.vpn.model.manual.connect + +import updated.mysterium.vpn.common.data.FormattedBytesViewItem + +data class ProviderState( + val active: Boolean, +) diff --git a/android/app/src/main/java/updated/mysterium/vpn/ui/connection/ConnectionViewModel.kt b/android/app/src/main/java/updated/mysterium/vpn/ui/connection/ConnectionViewModel.kt index 6d3a1332c..662722dad 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/ui/connection/ConnectionViewModel.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/ui/connection/ConnectionViewModel.kt @@ -160,6 +160,9 @@ class ConnectionViewModel(useCaseProvider: UseCaseProvider) : ViewModel() { private fun connectNode(proposal: Proposal, rate: Double) { exchangeRate = rate viewModelScope.launch(handler) { + coreService?.let { + it.startProvider(false) + } _connectionStatus.postValue(_connectionStatus.value?.copy(proposal = proposal)) disconnectIfConnectedNode() val req = ConnectRequest().apply { @@ -250,7 +253,7 @@ class ConnectionViewModel(useCaseProvider: UseCaseProvider) : ViewModel() { private suspend fun startDeferredNode() { if (!deferredNode.startedOrStarting()) { coreService?.let { - deferredNode.start(it, false) + deferredNode.start(it) } } connectionUseCase.initDeferredNode(deferredNode) diff --git a/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderActivity.kt b/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderActivity.kt index e69ba243b..12326af5f 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderActivity.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderActivity.kt @@ -2,8 +2,6 @@ package updated.mysterium.vpn.ui.provider import android.os.Bundle import android.view.View -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch import network.mysterium.vpn.databinding.ActivityProviderBinding import org.koin.android.ext.android.inject import updated.mysterium.vpn.App @@ -38,8 +36,8 @@ class ProviderActivity : BaseActivity() { private fun configure() { initToolbar(binding.manualConnectToolbar) - GlobalScope.launch { - binding.providerModeSwitch.isChecked = viewModel.getIsProvider() + viewModel.providerUpdate.observe(this) { + binding.providerModeSwitch.isChecked = it.active } } diff --git a/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderViewModel.kt b/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderViewModel.kt index 8f8d59e0b..7b4734e4a 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderViewModel.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderViewModel.kt @@ -1,11 +1,13 @@ package updated.mysterium.vpn.ui.provider import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.* -import updated.mysterium.vpn.core.DeferredNode import updated.mysterium.vpn.core.MysteriumCoreService +import updated.mysterium.vpn.model.manual.connect.ProviderState import updated.mysterium.vpn.network.provider.usecase.UseCaseProvider class ProviderViewModel(useCaseProvider: UseCaseProvider) : ViewModel() { @@ -14,8 +16,12 @@ class ProviderViewModel(useCaseProvider: UseCaseProvider) : ViewModel() { const val TAG = "ProviderViewModel" } - private var deferredNode = DeferredNode() + val providerUpdate: LiveData + get() = _providerUpdate + + private val _providerUpdate = MutableLiveData() private var coreService: MysteriumCoreService? = null + val handler = CoroutineExceptionHandler { _, exception -> Log.i(TAG, exception.localizedMessage ?: exception.toString()) } @@ -26,25 +32,34 @@ class ProviderViewModel(useCaseProvider: UseCaseProvider) : ViewModel() { println("ProviderViewModel > init") viewModelScope.launch(handler) { coreService = deferredMysteriumCoreService.await() + + val initialState = ProviderState( + active = getIsProvider(), + ) + _providerUpdate.postValue(initialState) } } fun toggleProvider(isChecked: Boolean) { + println ("MYDBG >>>>>>>>>>>> toggleProvider ! $isChecked") - viewModelScope.launch(handler) { + // which scope is correct ? + CoroutineScope(Dispatchers.IO).launch { coreService?.let { - if (isChecked) { - println ("MYDBG >>>>>>>>>>>> connect ! ") + if (it.isProviderActive()) { + return@let + } - it.setProviderActive(true) - deferredNode.start(it, true) - } else { - println ("MYDBG >>>>>>>>>>>> disconnect ! ") + // stop consumer + it.stopConsumer() + it.startProvider(true) - // disconnect - it.stopNode() - it.setProviderActive(false) + } else { + if (!it.isProviderActive()) { + return@let + } + it.startProvider(false) } } } @@ -56,5 +71,4 @@ class ProviderViewModel(useCaseProvider: UseCaseProvider) : ViewModel() { } return false } - } diff --git a/android/app/src/main/java/updated/mysterium/vpn/ui/splash/SplashViewModel.kt b/android/app/src/main/java/updated/mysterium/vpn/ui/splash/SplashViewModel.kt index 66f2f0a07..634d9d1db 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/ui/splash/SplashViewModel.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/ui/splash/SplashViewModel.kt @@ -67,7 +67,7 @@ class SplashViewModel( } } else { service?.let { - deferredNode.start(it, false) { exception -> + deferredNode.start(it) { exception -> if (exception != null) { _nodeStartingError.postValue(exception) } else { From 0780f29fedb45445d55d2def23099aca0d7fc21c Mon Sep 17 00:00:00 2001 From: Anton Litvinov Date: Thu, 15 Dec 2022 19:23:49 +0400 Subject: [PATCH 04/11] Remove debug output --- .../main/java/updated/mysterium/vpn/core/DeferredNode.kt | 2 -- .../mysterium/vpn/core/MysteriumAndroidCoreService.kt | 9 --------- 2 files changed, 11 deletions(-) diff --git a/android/app/src/main/java/updated/mysterium/vpn/core/DeferredNode.kt b/android/app/src/main/java/updated/mysterium/vpn/core/DeferredNode.kt index c4349ed95..6fb52c35e 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/core/DeferredNode.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/core/DeferredNode.kt @@ -23,8 +23,6 @@ class DeferredNode { service: MysteriumCoreService, done: ((err: Exception?) -> Unit)? = null ) { - println("MYDBG > DeferredNode.start") - if (!lock.tryAcquire()) { Log.i(TAG, "Node is already started or starting, skipping") diff --git a/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumAndroidCoreService.kt b/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumAndroidCoreService.kt index da8949e5f..aa4dcf9ac 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumAndroidCoreService.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumAndroidCoreService.kt @@ -74,12 +74,7 @@ class MysteriumAndroidCoreService : VpnService(), KoinComponent { private var secondsBetweenAnalyticEvent = 0 private var isProviderActive = false - init { - println("MYDBG > MysteriumAndroidCoreService") - } override fun onDestroy() { - println("MYDBG > onDestroy") - stopMobileNode() super.onDestroy() } @@ -93,7 +88,6 @@ class MysteriumAndroidCoreService : VpnService(), KoinComponent { } private fun startMobileProviderService(active: Boolean) { - println("MYDBG > startMobileProviderService") mobileNode?.let { try { isProviderActive = active @@ -109,7 +103,6 @@ class MysteriumAndroidCoreService : VpnService(), KoinComponent { } private fun innerStopConsumer() { - println("MYDBG > stopConsumer >") var c = currentState == ConnectionState.CONNECTED || currentState == ConnectionState.CONNECTING || currentState == ConnectionState.ON_HOLD || @@ -128,7 +121,6 @@ class MysteriumAndroidCoreService : VpnService(), KoinComponent { } private fun startMobileNode(filesPath: String): MobileNode { - println("MYDBG > startMobileNode $filesPath") mobileNode?.let { return it } @@ -138,7 +130,6 @@ class MysteriumAndroidCoreService : VpnService(), KoinComponent { } private fun stopMobileNode() { - println("MYDBG > stopMobileNode") val node = mobileNode if (node == null) { Log.w(TAG, "Trying to stop node when instance is not set") From 8f1774774c8f53530c9a91e9c53df54758762407 Mon Sep 17 00:00:00 2001 From: Anton Litvinov Date: Fri, 13 Jan 2023 18:01:25 +0400 Subject: [PATCH 05/11] Set default activity to Menu --- .../mysterium/vpn/core/MysteriumAndroidCoreService.kt | 2 +- .../main/java/updated/mysterium/vpn/ui/base/BaseActivity.kt | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumAndroidCoreService.kt b/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumAndroidCoreService.kt index c1f4a71d3..78fc03aac 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumAndroidCoreService.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumAndroidCoreService.kt @@ -124,7 +124,7 @@ class MysteriumAndroidCoreService : VpnService(), KoinComponent { mobileNode?.let { return it } - mobileNode = Mysterium.newNode(filesPath, Mysterium.defaultNodeOptions()) + mobileNode = Mysterium.newNode(filesPath, Mysterium.defaultProviderNodeOptions()) mobileNode?.overrideWireguardConnection(WireguardAndroidTunnelSetup(this@MysteriumAndroidCoreService)) return mobileNode ?: MobileNode() } diff --git a/android/app/src/main/java/updated/mysterium/vpn/ui/base/BaseActivity.kt b/android/app/src/main/java/updated/mysterium/vpn/ui/base/BaseActivity.kt index 8ed47d6e7..cde19dce7 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/ui/base/BaseActivity.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/ui/base/BaseActivity.kt @@ -35,6 +35,9 @@ import updated.mysterium.vpn.ui.connection.ConnectionActivity import updated.mysterium.vpn.ui.custom.view.ConnectionToolbar import updated.mysterium.vpn.ui.home.selection.HomeSelectionActivity import updated.mysterium.vpn.ui.home.selection.HomeSelectionViewModel +import updated.mysterium.vpn.ui.menu.MenuActivity +import updated.mysterium.vpn.ui.provider.ProviderActivity + import java.util.* abstract class BaseActivity : AppCompatActivity() { @@ -266,7 +269,7 @@ abstract class BaseActivity : AppCompatActivity() { ) { Intent(this, ConnectionActivity::class.java) } else { - Intent(this, HomeSelectionActivity::class.java) + Intent(this, MenuActivity::class.java) } intent.apply { flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK From 28f8e2e8820a13318fae5b072c33ee4cdd8b423b Mon Sep 17 00:00:00 2001 From: Anton Litvinov Date: Fri, 27 Jan 2023 01:30:36 +0400 Subject: [PATCH 06/11] * Display provider service status in provider activity * Add foreground notification to prevent app exit --- .../vpn/core/MysteriumAndroidCoreService.kt | 3 +- .../mysterium/vpn/core/NodeRepository.kt | 11 +++ .../vpn/model/manual/connect/ProviderState.kt | 7 +- .../notification/NotificationChannels.kt | 1 + .../vpn/network/usecase/ConnectionUseCase.kt | 5 ++ .../notification/AppNotificationManager.kt | 22 +++++ .../vpn/ui/provider/ProviderActivity.kt | 17 ++++ .../vpn/ui/provider/ProviderViewModel.kt | 52 ++++++++--- .../src/main/res/layout/activity_provider.xml | 87 ++++++++++++++++++- android/app/src/main/res/values/strings.xml | 8 ++ 10 files changed, 198 insertions(+), 15 deletions(-) diff --git a/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumAndroidCoreService.kt b/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumAndroidCoreService.kt index 78fc03aac..155fee9de 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumAndroidCoreService.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/core/MysteriumAndroidCoreService.kt @@ -89,14 +89,15 @@ class MysteriumAndroidCoreService : VpnService(), KoinComponent { private fun startMobileProviderService(active: Boolean) { mobileNode?.let { + isProviderActive = active try { - isProviderActive = active if (active) { it.startProvider() } else { it.stopProvider() } } catch (e: Exception) { + isProviderActive = !active println(e) } } diff --git a/android/app/src/main/java/updated/mysterium/vpn/core/NodeRepository.kt b/android/app/src/main/java/updated/mysterium/vpn/core/NodeRepository.kt index 14f9916d9..4cd5e98f0 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/core/NodeRepository.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/core/NodeRepository.kt @@ -19,6 +19,7 @@ import updated.mysterium.vpn.model.identity.MigrateHermesStatus import updated.mysterium.vpn.model.identity.MigrateHermesStatusResponse import updated.mysterium.vpn.model.manual.connect.ConnectionState import updated.mysterium.vpn.model.manual.connect.CountryInfo +import updated.mysterium.vpn.model.manual.connect.ServiceStatus import updated.mysterium.vpn.model.nodes.ProposalItem import updated.mysterium.vpn.model.nodes.ProposalsResponse import updated.mysterium.vpn.model.payment.Order @@ -71,6 +72,16 @@ class NodeRepository(var deferredNode: DeferredNode) { } } + // Register service status callback. + suspend fun registerServiceStatusChangeCallback(cb: (stats: ServiceStatus) -> Unit) { + withContext(Dispatchers.IO) { + deferredNode.await() + .registerServiceStatusChangeCallback { service, status -> + cb(ServiceStatus(service, status)) + } + } + } + // Register statistics callback. suspend fun registerStatisticsChangeCallback(cb: (stats: Statistics) -> Unit) { withContext(Dispatchers.IO) { diff --git a/android/app/src/main/java/updated/mysterium/vpn/model/manual/connect/ProviderState.kt b/android/app/src/main/java/updated/mysterium/vpn/model/manual/connect/ProviderState.kt index 7aac16660..e8a3f58c5 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/model/manual/connect/ProviderState.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/model/manual/connect/ProviderState.kt @@ -1,7 +1,10 @@ package updated.mysterium.vpn.model.manual.connect -import updated.mysterium.vpn.common.data.FormattedBytesViewItem - data class ProviderState( val active: Boolean, ) + +class ServiceStatus( + val service: String, + val status: String +) diff --git a/android/app/src/main/java/updated/mysterium/vpn/model/notification/NotificationChannels.kt b/android/app/src/main/java/updated/mysterium/vpn/model/notification/NotificationChannels.kt index 8d0853d73..581a0cac6 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/model/notification/NotificationChannels.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/model/notification/NotificationChannels.kt @@ -7,4 +7,5 @@ object NotificationChannels { const val BALANCE_NOTIFICATION_ID = 4 const val PRIVATE_KEY_NOTIFICATION_ID = 5 const val PAYMENT_STATUS_ID = 6 + const val PROVIDER_NOTIFICATION = 7 } diff --git a/android/app/src/main/java/updated/mysterium/vpn/network/usecase/ConnectionUseCase.kt b/android/app/src/main/java/updated/mysterium/vpn/network/usecase/ConnectionUseCase.kt index 597906bf4..322ebf0ff 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/network/usecase/ConnectionUseCase.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/network/usecase/ConnectionUseCase.kt @@ -9,6 +9,7 @@ import updated.mysterium.vpn.core.NodeRepository import updated.mysterium.vpn.database.preferences.SharedPreferencesList import updated.mysterium.vpn.database.preferences.SharedPreferencesManager import updated.mysterium.vpn.model.manual.connect.ConnectionState +import updated.mysterium.vpn.model.manual.connect.ServiceStatus import updated.mysterium.vpn.model.statistics.Statistics import updated.mysterium.vpn.model.wallet.Identity @@ -79,6 +80,10 @@ class ConnectionUseCase( callback: (Statistics) -> Unit ) = nodeRepository.registerStatisticsChangeCallback(callback) + suspend fun serviceStatusChangeCallback( + callback: (ServiceStatus) -> Unit + ) = nodeRepository.registerServiceStatusChangeCallback(callback) + suspend fun connectionStatusCallback( callback: (String) -> Unit ) = nodeRepository.registerConnectionStatusChangeCallback(callback) diff --git a/android/app/src/main/java/updated/mysterium/vpn/notification/AppNotificationManager.kt b/android/app/src/main/java/updated/mysterium/vpn/notification/AppNotificationManager.kt index ab4bc2823..c23b5afe2 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/notification/AppNotificationManager.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/notification/AppNotificationManager.kt @@ -8,6 +8,7 @@ import androidx.core.app.NotificationCompat import network.mysterium.vpn.R import updated.mysterium.vpn.model.notification.NotificationChannels import updated.mysterium.vpn.ui.connection.ConnectionActivity +import updated.mysterium.vpn.ui.provider.ProviderActivity import updated.mysterium.vpn.ui.splash.SplashActivity import updated.mysterium.vpn.ui.splash.SplashActivity.Companion.REDIRECTED_FROM_PUSH_KEY @@ -19,6 +20,7 @@ class AppNotificationManager(private val notificationManager: NotificationManage const val ACTION_DISCONNECT = "DISCONNECT" } + private val providerChannel = "provider" private val statisticsChannel = "statistics" private val connLostChannel = "connectionlost" private val paymentStatusChannel = "paymentstatus" @@ -28,6 +30,7 @@ class AppNotificationManager(private val notificationManager: NotificationManage // pendingAppIntent is used to navigate back to MainActivity // when user taps on notification. private lateinit var pendingAppIntent: PendingIntent + private lateinit var pendingProviderIntent: PendingIntent fun init(ctx: Context) { context = ctx @@ -36,11 +39,17 @@ class AppNotificationManager(private val notificationManager: NotificationManage } pendingAppIntent = PendingIntent.getActivity(ctx, 0, intent, PendingIntent.FLAG_IMMUTABLE) + val intentProvider = Intent(ctx, ProviderActivity::class.java).apply { + flags = Intent.FLAG_ACTIVITY_SINGLE_TOP + } + pendingProviderIntent = PendingIntent.getActivity(ctx, 0, intentProvider, PendingIntent.FLAG_IMMUTABLE) + registerAllNotificationChannels(context) } private fun registerAllNotificationChannels(context: Context) { with(context) { + createChannel(providerChannel, getString(R.string.provider_notification_chanel)) createChannel(statisticsChannel, getString(R.string.statisctics_notification_chanel)) createChannel(connLostChannel, getString(R.string.connection_lost_notification_chanel)) createChannel(paymentStatusChannel, getString(R.string.payment_notification_chanel)) @@ -72,6 +81,19 @@ class AppNotificationManager(private val notificationManager: NotificationManage } } + fun createProviderNotification(): NotificationFactory { + return { + NotificationCompat.Builder(it, providerChannel) + .setSmallIcon(R.drawable.notification_logo) + .setContentTitle("Provider is active") + .setPriority(NotificationCompat.PRIORITY_DEFAULT) + .setVibrate(LongArray(0)) + .setContentIntent(pendingProviderIntent) + .setOnlyAlertOnce(true) + .build() + } + } + fun showStatisticsNotification(title: String, content: String) { val disconnectIntent = Intent(context, AppBroadcastReceiver::class.java).apply { action = ACTION_DISCONNECT diff --git a/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderActivity.kt b/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderActivity.kt index 12326af5f..8dd721170 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderActivity.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderActivity.kt @@ -2,9 +2,11 @@ package updated.mysterium.vpn.ui.provider import android.os.Bundle import android.view.View +import network.mysterium.vpn.R import network.mysterium.vpn.databinding.ActivityProviderBinding import org.koin.android.ext.android.inject import updated.mysterium.vpn.App +import updated.mysterium.vpn.notification.AppNotificationManager import updated.mysterium.vpn.ui.base.BaseActivity class ProviderActivity : BaseActivity() { @@ -15,6 +17,8 @@ class ProviderActivity : BaseActivity() { private lateinit var binding: ActivityProviderBinding private val viewModel: ProviderViewModel by inject() + private val notificationManager: AppNotificationManager by inject() + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -23,6 +27,7 @@ class ProviderActivity : BaseActivity() { viewModel.init( deferredMysteriumCoreService = App.getInstance(this).deferredMysteriumCoreService, + notificationManager = notificationManager ) configure() bindsAction() @@ -39,6 +44,18 @@ class ProviderActivity : BaseActivity() { viewModel.providerUpdate.observe(this) { binding.providerModeSwitch.isChecked = it.active } + + viewModel.providerServiceStatus.observe(this) { + fun getStatusTxt(a: Boolean): Int { + if (a) { + return R.string.service_active_title; + } + return R.string.service_idle_title + } + binding.titleSvcState1.setText(getStatusTxt(it.active1)) + binding.titleSvcState2.setText(getStatusTxt(it.active2)) + binding.titleSvcState3.setText(getStatusTxt(it.active3)) + } } private fun bindsAction() { diff --git a/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderViewModel.kt b/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderViewModel.kt index 7b4734e4a..0b89b7f55 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderViewModel.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderViewModel.kt @@ -7,8 +7,17 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.* import updated.mysterium.vpn.core.MysteriumCoreService +import updated.mysterium.vpn.model.manual.connect.ConnectionState import updated.mysterium.vpn.model.manual.connect.ProviderState +import updated.mysterium.vpn.model.notification.NotificationChannels import updated.mysterium.vpn.network.provider.usecase.UseCaseProvider +import updated.mysterium.vpn.notification.AppNotificationManager + +data class ProviderService( + var active1: Boolean, + var active2: Boolean, + var active3: Boolean, +) class ProviderViewModel(useCaseProvider: UseCaseProvider) : ViewModel() { @@ -16,11 +25,21 @@ class ProviderViewModel(useCaseProvider: UseCaseProvider) : ViewModel() { const val TAG = "ProviderViewModel" } + val providerUpdate: LiveData get() = _providerUpdate - private val _providerUpdate = MutableLiveData() + + + private val servicesState = ProviderService(false,false,false) + val providerServiceStatus: LiveData + get() = _providerServiceStatus + private val _providerServiceStatus = MutableLiveData() + + private var coreService: MysteriumCoreService? = null + private val connectionUseCase = useCaseProvider.connection() + private lateinit var appNotificationManager: AppNotificationManager val handler = CoroutineExceptionHandler { _, exception -> Log.i(TAG, exception.localizedMessage ?: exception.toString()) @@ -28,22 +47,30 @@ class ProviderViewModel(useCaseProvider: UseCaseProvider) : ViewModel() { fun init( deferredMysteriumCoreService: CompletableDeferred, - ) { - println("ProviderViewModel > init") + notificationManager: AppNotificationManager, + ) { viewModelScope.launch(handler) { + appNotificationManager = notificationManager coreService = deferredMysteriumCoreService.await() val initialState = ProviderState( active = getIsProvider(), ) _providerUpdate.postValue(initialState) + + connectionUseCase.serviceStatusChangeCallback { + val running = (it.status == "Running") + when (it.service) { + "wireguard" -> servicesState.active1 = running + "data_transfer" -> servicesState.active2 = running + "scraping" -> servicesState.active3 = running + } + _providerServiceStatus.postValue(servicesState) + } } } fun toggleProvider(isChecked: Boolean) { - println ("MYDBG >>>>>>>>>>>> toggleProvider ! $isChecked") - - // which scope is correct ? CoroutineScope(Dispatchers.IO).launch { coreService?.let { if (isChecked) { @@ -51,21 +78,26 @@ class ProviderViewModel(useCaseProvider: UseCaseProvider) : ViewModel() { return@let } - // stop consumer - it.stopConsumer() it.startProvider(true) - + it.startForegroundWithNotification( + NotificationChannels.PROVIDER_NOTIFICATION, + appNotificationManager.createProviderNotification() + ) } else { if (!it.isProviderActive()) { return@let } + it.startProvider(false) + it.stopForeground() } } + + } } - suspend fun getIsProvider(): Boolean { + private suspend fun getIsProvider(): Boolean { coreService?.let { return it.isProviderActive() } diff --git a/android/app/src/main/res/layout/activity_provider.xml b/android/app/src/main/res/layout/activity_provider.xml index 7cc4455f0..152fe59c0 100644 --- a/android/app/src/main/res/layout/activity_provider.xml +++ b/android/app/src/main/res/layout/activity_provider.xml @@ -51,8 +51,8 @@ + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 6840957d8..3e7252764 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -204,6 +204,12 @@ Settings Identity is your Mysterium internal user ID. Never send ether or any kind of ERC20 tokens there. DNS + wireguard + data transfer + scraping + idle + active + Resident country System Provider @@ -325,4 +331,6 @@ Lost Connection Payments Reminder Notifications + Provider mode + From cd080baffdcfa4b8eafc9269c752122cc56e2054 Mon Sep 17 00:00:00 2001 From: Anton Litvinov Date: Mon, 30 Jan 2023 20:59:44 +0400 Subject: [PATCH 07/11] Make ProviderViewModel instance a single to prevent a loss of service activity status --- .../java/updated/mysterium/vpn/di/Modules.kt | 2 +- .../vpn/ui/connection/ConnectionViewModel.kt | 3 -- .../vpn/ui/provider/ProviderActivity.kt | 18 +++++++-- .../vpn/ui/provider/ProviderViewModel.kt | 19 ++++------ .../src/main/res/layout/activity_provider.xml | 38 +++++++++++++++++-- 5 files changed, 59 insertions(+), 21 deletions(-) diff --git a/android/app/src/main/java/updated/mysterium/vpn/di/Modules.kt b/android/app/src/main/java/updated/mysterium/vpn/di/Modules.kt index 66761643f..91fb460cd 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/di/Modules.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/di/Modules.kt @@ -159,7 +159,7 @@ object Modules { viewModel { SelectCountryViewModel(get()) } - viewModel { + single { ProviderViewModel(get()) } } diff --git a/android/app/src/main/java/updated/mysterium/vpn/ui/connection/ConnectionViewModel.kt b/android/app/src/main/java/updated/mysterium/vpn/ui/connection/ConnectionViewModel.kt index ebe7e5db9..170c13c92 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/ui/connection/ConnectionViewModel.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/ui/connection/ConnectionViewModel.kt @@ -161,9 +161,6 @@ class ConnectionViewModel(useCaseProvider: UseCaseProvider) : ViewModel() { private fun connectNode(proposal: Proposal, rate: Double) { exchangeRate = rate viewModelScope.launch(handler) { - coreService?.let { - it.startProvider(false) - } _connectionStatus.postValue(_connectionStatus.value?.copy(proposal = proposal)) disconnectIfConnectedNode() val req = ConnectRequest().apply { diff --git a/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderActivity.kt b/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderActivity.kt index 8dd721170..393d2097a 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderActivity.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderActivity.kt @@ -1,5 +1,8 @@ package updated.mysterium.vpn.ui.provider +import android.content.ActivityNotFoundException +import android.content.Intent +import android.net.Uri import android.os.Bundle import android.view.View import network.mysterium.vpn.R @@ -9,6 +12,7 @@ import updated.mysterium.vpn.App import updated.mysterium.vpn.notification.AppNotificationManager import updated.mysterium.vpn.ui.base.BaseActivity + class ProviderActivity : BaseActivity() { private companion object { @@ -52,9 +56,9 @@ class ProviderActivity : BaseActivity() { } return R.string.service_idle_title } - binding.titleSvcState1.setText(getStatusTxt(it.active1)) - binding.titleSvcState2.setText(getStatusTxt(it.active2)) - binding.titleSvcState3.setText(getStatusTxt(it.active3)) + binding.titleSvcState1.setText(getStatusTxt(it.active[0])) + binding.titleSvcState2.setText(getStatusTxt(it.active[1])) + binding.titleSvcState3.setText(getStatusTxt(it.active[2])) } } @@ -68,6 +72,14 @@ class ProviderActivity : BaseActivity() { binding.providerModeSwitch.setOnCheckedChangeListener { _, isChecked -> viewModel.toggleProvider(isChecked) } + binding.buttonUI.setOnClickListener { + try { + val myIntent = Intent(Intent.ACTION_VIEW, Uri.parse("http://localhost:4449")) + startActivity(myIntent) + } catch (e: ActivityNotFoundException) { + e.printStackTrace() + } + } } } diff --git a/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderViewModel.kt b/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderViewModel.kt index 0b89b7f55..df070d5c7 100644 --- a/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderViewModel.kt +++ b/android/app/src/main/java/updated/mysterium/vpn/ui/provider/ProviderViewModel.kt @@ -7,16 +7,13 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.* import updated.mysterium.vpn.core.MysteriumCoreService -import updated.mysterium.vpn.model.manual.connect.ConnectionState import updated.mysterium.vpn.model.manual.connect.ProviderState import updated.mysterium.vpn.model.notification.NotificationChannels import updated.mysterium.vpn.network.provider.usecase.UseCaseProvider import updated.mysterium.vpn.notification.AppNotificationManager -data class ProviderService( - var active1: Boolean, - var active2: Boolean, - var active3: Boolean, +data class ServiceState( + var active: Array, ) class ProviderViewModel(useCaseProvider: UseCaseProvider) : ViewModel() { @@ -31,10 +28,10 @@ class ProviderViewModel(useCaseProvider: UseCaseProvider) : ViewModel() { private val _providerUpdate = MutableLiveData() - private val servicesState = ProviderService(false,false,false) - val providerServiceStatus: LiveData + private val servicesState = ServiceState( Array(3) {false} ) + val providerServiceStatus: LiveData get() = _providerServiceStatus - private val _providerServiceStatus = MutableLiveData() + private val _providerServiceStatus = MutableLiveData() private var coreService: MysteriumCoreService? = null @@ -61,9 +58,9 @@ class ProviderViewModel(useCaseProvider: UseCaseProvider) : ViewModel() { connectionUseCase.serviceStatusChangeCallback { val running = (it.status == "Running") when (it.service) { - "wireguard" -> servicesState.active1 = running - "data_transfer" -> servicesState.active2 = running - "scraping" -> servicesState.active3 = running + "wireguard" -> servicesState.active[0] = running + "data_transfer" -> servicesState.active[1] = running + "scraping" -> servicesState.active[2] = running } _providerServiceStatus.postValue(servicesState) } diff --git a/android/app/src/main/res/layout/activity_provider.xml b/android/app/src/main/res/layout/activity_provider.xml index 152fe59c0..214c3de3e 100644 --- a/android/app/src/main/res/layout/activity_provider.xml +++ b/android/app/src/main/res/layout/activity_provider.xml @@ -52,7 +52,7 @@ @@ -107,6 +110,7 @@ android:layout_marginTop="144dp" android:text="@string/service_idle_title" android:textColor="@android:color/white" + android:textSize="14sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.433" app:layout_constraintStart_toStartOf="parent" @@ -120,6 +124,7 @@ android:layout_marginTop="176dp" android:text="@string/service_idle_title" android:textColor="@android:color/white" + android:textSize="14sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.433" app:layout_constraintStart_toStartOf="parent" @@ -133,6 +138,7 @@ android:layout_marginTop="176dp" android:text="@string/service_2_title" android:textColor="@android:color/white" + android:textSize="14sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.058" app:layout_constraintStart_toStartOf="parent" @@ -146,8 +152,9 @@ android:layout_marginTop="208dp" android:text="@string/service_3_title" android:textColor="@android:color/white" + android:textSize="14sp" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHorizontal_bias="0.058" + app:layout_constraintHorizontal_bias="0.049" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> @@ -213,6 +220,31 @@ +