Skip to content

Commit

Permalink
Refactoring NetworkMonitor to be more Java friendly
Browse files Browse the repository at this point in the history
Signed-off-by: rapterjet2004 <juliuslinus1@gmail.com>
  • Loading branch information
rapterjet2004 committed Nov 19, 2024
1 parent 29dd023 commit c084fbd
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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>
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -29,54 +29,46 @@ import javax.inject.Singleton
class NetworkMonitorImpl @Inject constructor(
private val context: Context
) : NetworkMonitor {
override val isOnline: Flow<Boolean> = callbackFlow {
trace("NetworkMonitorImpl.callbackFlow") {
val connectivityManager = context.getSystemService<ConnectivityManager>()
if (connectivityManager == null) {
channel.trySend(false)
channel.close()
return@callbackFlow
}
override val isOnlineLiveData: LiveData<Boolean>
get() = isOnline.asLiveData()

/**
* 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() {
override val isOnline: Flow<Boolean> = callbackFlow {
val connectivityManager = context.getSystemService<ConnectivityManager>()
if (connectivityManager == null) {
channel.trySend(false)
channel.close()
return@callbackFlow
}

private val networks = mutableSetOf<Network>()
val networkRequest = Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build()

override fun onAvailable(network: Network) {
networks += network
channel.trySend(true)
}
val networkCallback = object : ConnectivityManager.NetworkCallback() {
private val networks = mutableSetOf<Network>()

override fun onLost(network: Network) {
networks -= network
channel.trySend(networks.isNotEmpty())
}
override fun onAvailable(network: Network) {
networks += network
channel.trySend(true)
}

trace("NetworkMonitorImpl.registerNetworkCallback") {
val request = Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build()
connectivityManager.registerNetworkCallback(request, callback)
override fun onLost(network: Network) {
networks -= network
channel.trySend(networks.isNotEmpty())
}
}

/**
* Sends the latest connectivity status to the underlying channel.
*/
channel.trySend(connectivityManager.isCurrentlyConnected())
connectivityManager.registerNetworkCallback(networkRequest, networkCallback)

awaitClose {
connectivityManager.unregisterNetworkCallback(callback)
}
channel.trySend(connectivityManager.isCurrentlyConnected())

awaitClose {
connectivityManager.unregisterNetworkCallback(networkCallback)
}
}
.distinctUntilChanged()
.flowOn(Dispatchers.IO)
.conflate()
.distinctUntilChanged()
.flowOn(Dispatchers.IO)
.conflate()

private fun ConnectivityManager.isCurrentlyConnected() =
activeNetwork
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,7 @@

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;
Expand All @@ -28,6 +24,7 @@
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;
Expand Down Expand Up @@ -87,6 +84,9 @@ public class ChooseAccountDialogFragment extends DialogFragment {
@Inject
InvitationsRepository invitationsRepository;

@Inject
NetworkMonitor networkMonitor;

private DialogChooseAccountBinding binding;
private View dialogView;

Expand Down Expand Up @@ -115,7 +115,7 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
setupCurrentUser(user);
setupListeners();
setupAdapter();
prepareViews();
networkMonitor.isOnlineLiveData().observe(this, this::prepareViews);
}

private void setupCurrentUser(User user) {
Expand Down Expand Up @@ -265,29 +265,6 @@ private void themeViews() {
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());

Expand Down Expand Up @@ -336,15 +313,15 @@ public void onComplete() {
}
}

private void prepareViews() {
private void prepareViews(Boolean isOnline) {
if (getActivity() != null) {
LinearLayoutManager layoutManager = new SmoothScrollLinearLayoutManager(getActivity());
binding.accountsList.setLayoutManager(layoutManager);
}
binding.accountsList.setHasFixedSize(true);
binding.accountsList.setAdapter(adapter);

if (!isNetworkAvailable(getContext())) {
if (!isOnline) {
binding.addAccount.setVisibility(View.GONE);
}
}
Expand Down

0 comments on commit c084fbd

Please sign in to comment.