Loading app/src/main/java/foundation/e/apps/MainActivity.kt +8 −11 Original line number Diff line number Diff line Loading @@ -80,8 +80,6 @@ class MainActivity : AppCompatActivity() { val (bottomNavigationView, navController) = setupBootomNav() var hasInternet = true setupViewModels() setupNavigations(navController) Loading @@ -94,13 +92,14 @@ class MainActivity : AppCompatActivity() { viewModel.createNotificationChannels() } viewModel.setupConnectivityManager(this.applicationContext) hasInternet = observeInternetConnections(hasInternet) observeInternetConnections() observeAuthObjects(navController) setupDestinationChangedListener(navController, hasInternet, bottomNavigationView) setupDestinationChangedListener(navController, bottomNavigationView) observePurchaseAppPage() Loading @@ -121,6 +120,7 @@ class MainActivity : AppCompatActivity() { observeEvents() } private fun setupNavigations(navController: NavController) { val navOptions = NavOptions.Builder() .setPopUpTo(R.id.navigation_resource, true) Loading Loading @@ -207,25 +207,22 @@ class MainActivity : AppCompatActivity() { } } private fun observeInternetConnections(hasInternet: Boolean): Boolean { var mutableHasInternet = hasInternet viewModel.internetConnection.observe(this) { isInternetAvailable -> mutableHasInternet = isInternetAvailable private fun observeInternetConnections() { viewModel.internetConnection.distinctUntilChanged().observe(this) { isInternetAvailable -> Timber.d("Observe internetConnection: $isInternetAvailable") if (isInternetAvailable) { binding.noInternet.visibility = View.GONE binding.fragment.visibility = View.VISIBLE } } return mutableHasInternet } private fun setupDestinationChangedListener( navController: NavController, hasInternet: Boolean, bottomNavigationView: BottomNavigationView ) { navController.addOnDestinationChangedListener { _, destination, _ -> if (!hasInternet) { if (viewModel.internetConnection.value == false) { showNoInternet() } when (destination.id) { Loading app/src/main/java/foundation/e/apps/ui/MainActivityViewModel.kt +3 −70 Original line number Diff line number Diff line Loading @@ -21,9 +21,6 @@ package foundation.e.apps.ui import android.content.Context import android.content.Intent import android.net.ConnectivityManager import android.net.Network import android.net.NetworkCapabilities import android.net.NetworkRequest import android.os.Build import androidx.annotation.RequiresApi import androidx.appcompat.app.AlertDialog Loading @@ -31,7 +28,6 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.asLiveData import androidx.lifecycle.distinctUntilChanged import androidx.lifecycle.viewModelScope import com.aurora.gplayapi.data.models.AuthData import dagger.hilt.android.lifecycle.HiltViewModel Loading @@ -50,9 +46,7 @@ import foundation.e.apps.install.pkg.PWAManager import foundation.e.apps.install.pkg.AppLoungePackageManager import foundation.e.apps.install.workmanager.AppInstallProcessor import foundation.e.apps.data.preference.getSync import kotlinx.coroutines.channels.ProducerScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.callbackFlow import foundation.e.apps.utils.NetworkStatusManager import kotlinx.coroutines.launch import javax.inject.Inject Loading @@ -74,6 +68,7 @@ class MainActivityViewModel @Inject constructor( val purchaseAppLiveData: LiveData<FusedDownload> = _purchaseAppLiveData val isAppPurchased: MutableLiveData<String> = MutableLiveData() val purchaseDeclined: MutableLiveData<String> = MutableLiveData() lateinit var internetConnection: LiveData<Boolean> var gPlayAuthData = AuthData("", "") Loading Loading @@ -210,69 +205,7 @@ class MainActivityViewModel @Inject constructor( } fun setupConnectivityManager(context: Context) { connectivityManager = context.getSystemService(ConnectivityManager::class.java) as ConnectivityManager } val internetConnection = callbackFlow { if (!this@MainActivityViewModel::connectivityManager.isInitialized) { awaitClose { } return@callbackFlow } sendInternetStatus(connectivityManager) val networkCallback = getNetworkCallback(this) connectivityManager.registerNetworkCallback(networkRequest, networkCallback) awaitClose { connectivityManager.unregisterNetworkCallback(networkCallback) } }.asLiveData().distinctUntilChanged() private val networkRequest = NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .build() private fun getNetworkCallback( callbackFlowScope: ProducerScope<Boolean>, ): ConnectivityManager.NetworkCallback { return object : ConnectivityManager.NetworkCallback() { override fun onAvailable(network: Network) { super.onAvailable(network) callbackFlowScope.sendInternetStatus(connectivityManager) } override fun onCapabilitiesChanged( network: Network, networkCapabilities: NetworkCapabilities ) { super.onCapabilitiesChanged(network, networkCapabilities) callbackFlowScope.sendInternetStatus(connectivityManager) } override fun onLost(network: Network) { super.onLost(network) callbackFlowScope.sendInternetStatus(connectivityManager) } } } // protected to avoid SyntheticAccessor protected fun ProducerScope<Boolean>.sendInternetStatus(connectivityManager: ConnectivityManager) { val capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork) val hasInternet = capabilities != null && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) trySend(hasInternet) internetConnection = NetworkStatusManager.init(context) } fun updateStatusOfFusedApps( Loading app/src/main/java/foundation/e/apps/utils/NetworkStatusManager.kt 0 → 100644 +91 −0 Original line number Diff line number Diff line /* * Copyright MURENA SAS 2024 * Apps Quickly and easily install Android apps onto your device! * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ package foundation.e.apps.utils import android.content.Context import android.net.ConnectivityManager import android.net.Network import android.net.NetworkCapabilities import android.net.NetworkRequest import androidx.lifecycle.MutableLiveData import timber.log.Timber object NetworkStatusManager { private lateinit var connectivityManager: ConnectivityManager private var internetConnectionLiveData: MutableLiveData<Boolean> = MutableLiveData() /** * Registers for network callback with [ConnectivityManager] * @param context should be applicationContext * @return [MutableLiveData], holds the [Boolean] value as status of internet availability */ fun init(context: Context): MutableLiveData<Boolean> { connectivityManager = context.getSystemService(ConnectivityManager::class.java) as ConnectivityManager val networkRequest = NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .build() connectivityManager.registerNetworkCallback(networkRequest, createNetworkCallback()) return internetConnectionLiveData } private fun createNetworkCallback( ): ConnectivityManager.NetworkCallback { return object : ConnectivityManager.NetworkCallback() { override fun onAvailable(network: Network) { super.onAvailable(network) Timber.d("Network: onAvailable: ${network.networkHandle}") sendInternetStatus(true) } override fun onCapabilitiesChanged( network: Network, networkCapabilities: NetworkCapabilities ) { super.onCapabilitiesChanged(network, networkCapabilities) val hasInternet = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) Timber.d("Network: onCapabilitiesChanged: ${network.networkHandle}, hasInternet: $hasInternet") sendInternetStatus(hasInternet) } override fun onLost(network: Network) { super.onLost(network) Timber.d("Network: onLost: ${network.networkHandle}") sendInternetStatus(false) } private fun sendInternetStatus(hasInternet: Boolean?) { hasInternet?.let { internetConnectionLiveData.postValue(it) } } } } } Loading
app/src/main/java/foundation/e/apps/MainActivity.kt +8 −11 Original line number Diff line number Diff line Loading @@ -80,8 +80,6 @@ class MainActivity : AppCompatActivity() { val (bottomNavigationView, navController) = setupBootomNav() var hasInternet = true setupViewModels() setupNavigations(navController) Loading @@ -94,13 +92,14 @@ class MainActivity : AppCompatActivity() { viewModel.createNotificationChannels() } viewModel.setupConnectivityManager(this.applicationContext) hasInternet = observeInternetConnections(hasInternet) observeInternetConnections() observeAuthObjects(navController) setupDestinationChangedListener(navController, hasInternet, bottomNavigationView) setupDestinationChangedListener(navController, bottomNavigationView) observePurchaseAppPage() Loading @@ -121,6 +120,7 @@ class MainActivity : AppCompatActivity() { observeEvents() } private fun setupNavigations(navController: NavController) { val navOptions = NavOptions.Builder() .setPopUpTo(R.id.navigation_resource, true) Loading Loading @@ -207,25 +207,22 @@ class MainActivity : AppCompatActivity() { } } private fun observeInternetConnections(hasInternet: Boolean): Boolean { var mutableHasInternet = hasInternet viewModel.internetConnection.observe(this) { isInternetAvailable -> mutableHasInternet = isInternetAvailable private fun observeInternetConnections() { viewModel.internetConnection.distinctUntilChanged().observe(this) { isInternetAvailable -> Timber.d("Observe internetConnection: $isInternetAvailable") if (isInternetAvailable) { binding.noInternet.visibility = View.GONE binding.fragment.visibility = View.VISIBLE } } return mutableHasInternet } private fun setupDestinationChangedListener( navController: NavController, hasInternet: Boolean, bottomNavigationView: BottomNavigationView ) { navController.addOnDestinationChangedListener { _, destination, _ -> if (!hasInternet) { if (viewModel.internetConnection.value == false) { showNoInternet() } when (destination.id) { Loading
app/src/main/java/foundation/e/apps/ui/MainActivityViewModel.kt +3 −70 Original line number Diff line number Diff line Loading @@ -21,9 +21,6 @@ package foundation.e.apps.ui import android.content.Context import android.content.Intent import android.net.ConnectivityManager import android.net.Network import android.net.NetworkCapabilities import android.net.NetworkRequest import android.os.Build import androidx.annotation.RequiresApi import androidx.appcompat.app.AlertDialog Loading @@ -31,7 +28,6 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.asLiveData import androidx.lifecycle.distinctUntilChanged import androidx.lifecycle.viewModelScope import com.aurora.gplayapi.data.models.AuthData import dagger.hilt.android.lifecycle.HiltViewModel Loading @@ -50,9 +46,7 @@ import foundation.e.apps.install.pkg.PWAManager import foundation.e.apps.install.pkg.AppLoungePackageManager import foundation.e.apps.install.workmanager.AppInstallProcessor import foundation.e.apps.data.preference.getSync import kotlinx.coroutines.channels.ProducerScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.callbackFlow import foundation.e.apps.utils.NetworkStatusManager import kotlinx.coroutines.launch import javax.inject.Inject Loading @@ -74,6 +68,7 @@ class MainActivityViewModel @Inject constructor( val purchaseAppLiveData: LiveData<FusedDownload> = _purchaseAppLiveData val isAppPurchased: MutableLiveData<String> = MutableLiveData() val purchaseDeclined: MutableLiveData<String> = MutableLiveData() lateinit var internetConnection: LiveData<Boolean> var gPlayAuthData = AuthData("", "") Loading Loading @@ -210,69 +205,7 @@ class MainActivityViewModel @Inject constructor( } fun setupConnectivityManager(context: Context) { connectivityManager = context.getSystemService(ConnectivityManager::class.java) as ConnectivityManager } val internetConnection = callbackFlow { if (!this@MainActivityViewModel::connectivityManager.isInitialized) { awaitClose { } return@callbackFlow } sendInternetStatus(connectivityManager) val networkCallback = getNetworkCallback(this) connectivityManager.registerNetworkCallback(networkRequest, networkCallback) awaitClose { connectivityManager.unregisterNetworkCallback(networkCallback) } }.asLiveData().distinctUntilChanged() private val networkRequest = NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .build() private fun getNetworkCallback( callbackFlowScope: ProducerScope<Boolean>, ): ConnectivityManager.NetworkCallback { return object : ConnectivityManager.NetworkCallback() { override fun onAvailable(network: Network) { super.onAvailable(network) callbackFlowScope.sendInternetStatus(connectivityManager) } override fun onCapabilitiesChanged( network: Network, networkCapabilities: NetworkCapabilities ) { super.onCapabilitiesChanged(network, networkCapabilities) callbackFlowScope.sendInternetStatus(connectivityManager) } override fun onLost(network: Network) { super.onLost(network) callbackFlowScope.sendInternetStatus(connectivityManager) } } } // protected to avoid SyntheticAccessor protected fun ProducerScope<Boolean>.sendInternetStatus(connectivityManager: ConnectivityManager) { val capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork) val hasInternet = capabilities != null && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) trySend(hasInternet) internetConnection = NetworkStatusManager.init(context) } fun updateStatusOfFusedApps( Loading
app/src/main/java/foundation/e/apps/utils/NetworkStatusManager.kt 0 → 100644 +91 −0 Original line number Diff line number Diff line /* * Copyright MURENA SAS 2024 * Apps Quickly and easily install Android apps onto your device! * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ package foundation.e.apps.utils import android.content.Context import android.net.ConnectivityManager import android.net.Network import android.net.NetworkCapabilities import android.net.NetworkRequest import androidx.lifecycle.MutableLiveData import timber.log.Timber object NetworkStatusManager { private lateinit var connectivityManager: ConnectivityManager private var internetConnectionLiveData: MutableLiveData<Boolean> = MutableLiveData() /** * Registers for network callback with [ConnectivityManager] * @param context should be applicationContext * @return [MutableLiveData], holds the [Boolean] value as status of internet availability */ fun init(context: Context): MutableLiveData<Boolean> { connectivityManager = context.getSystemService(ConnectivityManager::class.java) as ConnectivityManager val networkRequest = NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .build() connectivityManager.registerNetworkCallback(networkRequest, createNetworkCallback()) return internetConnectionLiveData } private fun createNetworkCallback( ): ConnectivityManager.NetworkCallback { return object : ConnectivityManager.NetworkCallback() { override fun onAvailable(network: Network) { super.onAvailable(network) Timber.d("Network: onAvailable: ${network.networkHandle}") sendInternetStatus(true) } override fun onCapabilitiesChanged( network: Network, networkCapabilities: NetworkCapabilities ) { super.onCapabilitiesChanged(network, networkCapabilities) val hasInternet = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) Timber.d("Network: onCapabilitiesChanged: ${network.networkHandle}, hasInternet: $hasInternet") sendInternetStatus(hasInternet) } override fun onLost(network: Network) { super.onLost(network) Timber.d("Network: onLost: ${network.networkHandle}") sendInternetStatus(false) } private fun sendInternetStatus(hasInternet: Boolean?) { hasInternet?.let { internetConnectionLiveData.postValue(it) } } } } }