Refactoring NetworkMonitor to be more Java friendly

Signed-off-by: rapterjet2004 <juliuslinus1@gmail.com>
This commit is contained in:
rapterjet2004 2024-11-19 09:08:08 -06:00
parent 29dd0231ae
commit c084fbd5ee
No known key found for this signature in database
GPG key ID: 3AA5FDFED7944099
3 changed files with 52 additions and 74 deletions

View file

@ -7,11 +7,20 @@
package com.nextcloud.talk.data.network
import androidx.lifecycle.LiveData
import kotlinx.coroutines.flow.Flow
/**
* Utility for reporting app connectivity status.
*/
interface NetworkMonitor {
/**
* Returns the device's current connectivity status.
*/
val isOnline: Flow<Boolean>
/**
* Returns the device's current connectivity status as LiveData for better interop with Java code.
*/
val isOnlineLiveData: LiveData<Boolean>
}

View file

@ -11,10 +11,10 @@ import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.net.NetworkRequest.Builder
import androidx.core.content.getSystemService
import androidx.core.os.trace
import androidx.lifecycle.LiveData
import androidx.lifecycle.asLiveData
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
@ -29,54 +29,46 @@ import javax.inject.Singleton
class NetworkMonitorImpl @Inject constructor(
private val context: Context
) : NetworkMonitor {
override val isOnlineLiveData: LiveData<Boolean>
get() = isOnline.asLiveData()
override val isOnline: Flow<Boolean> = callbackFlow {
trace("NetworkMonitorImpl.callbackFlow") {
val connectivityManager = context.getSystemService<ConnectivityManager>()
if (connectivityManager == null) {
channel.trySend(false)
channel.close()
return@callbackFlow
val connectivityManager = context.getSystemService<ConnectivityManager>()
if (connectivityManager == null) {
channel.trySend(false)
channel.close()
return@callbackFlow
}
val networkRequest = Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build()
val networkCallback = object : ConnectivityManager.NetworkCallback() {
private val networks = mutableSetOf<Network>()
override fun onAvailable(network: Network) {
networks += network
channel.trySend(true)
}
/**
* The callback's methods are invoked on changes to *any* network matching the [NetworkRequest],
* not just the active network. So we can simply track the presence (or absence) of such [Network].
*/
val callback = object : ConnectivityManager.NetworkCallback() {
private val networks = mutableSetOf<Network>()
override fun onAvailable(network: Network) {
networks += network
channel.trySend(true)
}
override fun onLost(network: Network) {
networks -= network
channel.trySend(networks.isNotEmpty())
}
}
trace("NetworkMonitorImpl.registerNetworkCallback") {
val request = Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build()
connectivityManager.registerNetworkCallback(request, callback)
}
/**
* Sends the latest connectivity status to the underlying channel.
*/
channel.trySend(connectivityManager.isCurrentlyConnected())
awaitClose {
connectivityManager.unregisterNetworkCallback(callback)
override fun onLost(network: Network) {
networks -= network
channel.trySend(networks.isNotEmpty())
}
}
connectivityManager.registerNetworkCallback(networkRequest, networkCallback)
channel.trySend(connectivityManager.isCurrentlyConnected())
awaitClose {
connectivityManager.unregisterNetworkCallback(networkCallback)
}
}
.distinctUntilChanged()
.flowOn(Dispatchers.IO)
.conflate()
.distinctUntilChanged()
.flowOn(Dispatchers.IO)
.conflate()
private fun ConnectivityManager.isCurrentlyConnected() =
activeNetwork

View file

@ -10,11 +10,7 @@ package com.nextcloud.talk.ui.dialog;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
@ -28,6 +24,7 @@ import com.nextcloud.talk.adapters.items.AdvancedUserItem;
import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.conversationlist.ConversationsListActivity;
import com.nextcloud.talk.data.network.NetworkMonitor;
import com.nextcloud.talk.data.user.model.User;
import com.nextcloud.talk.databinding.DialogChooseAccountBinding;
import com.nextcloud.talk.extensions.ImageViewExtensionsKt;
@ -87,6 +84,9 @@ public class ChooseAccountDialogFragment extends DialogFragment {
@Inject
InvitationsRepository invitationsRepository;
@Inject
NetworkMonitor networkMonitor;
private DialogChooseAccountBinding binding;
private View dialogView;
@ -115,7 +115,7 @@ public class ChooseAccountDialogFragment extends DialogFragment {
setupCurrentUser(user);
setupListeners();
setupAdapter();
prepareViews();
networkMonitor.isOnlineLiveData().observe(this, this::prepareViews);
}
private void setupCurrentUser(User user) {
@ -265,29 +265,6 @@ public class ChooseAccountDialogFragment extends DialogFragment {
viewThemeUtils.dialog.colorDialogMenuText(binding.manageSettings);
}
// Would have preferred to use NetworkMonitor but java with kotlin flows is ugly
public static boolean isNetworkAvailable(Context context) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager == null) {
return false;
}
Network network = connectivityManager.getActiveNetwork();
if (network == null) {
return false;
}
NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);
if (capabilities == null) {
return false;
}
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN) ||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET);
}
private void loadCurrentStatus(User user) {
String credentials = ApiUtils.getCredentials(user.getUsername(), user.getToken());
@ -336,7 +313,7 @@ public class ChooseAccountDialogFragment extends DialogFragment {
}
}
private void prepareViews() {
private void prepareViews(Boolean isOnline) {
if (getActivity() != null) {
LinearLayoutManager layoutManager = new SmoothScrollLinearLayoutManager(getActivity());
binding.accountsList.setLayoutManager(layoutManager);
@ -344,7 +321,7 @@ public class ChooseAccountDialogFragment extends DialogFragment {
binding.accountsList.setHasFixedSize(true);
binding.accountsList.setAdapter(adapter);
if (!isNetworkAvailable(getContext())) {
if (!isOnline) {
binding.addAccount.setVisibility(View.GONE);
}
}