Fixed
Status Update
Comments
vi...@google.com <vi...@google.com>
vi...@google.com <vi...@google.com> #2
Thank you for reporting this issue. We have shared this with our product and engineering team and will update this issue with more information as it becomes available.
For us to further investigate this issue, please provide the following additional information:
Expected output
What is the expected output?
Current output
What is the current output?
For us to further investigate this issue, please provide the following additional information:
Expected output
What is the expected output?
Current output
What is the current output?
pa...@gmail.com <pa...@gmail.com> #3
Expected Output : onAvailabe should fire when wifi is connected.
Current Output : onAvailable not fired but the below events are fired.
onLinkPropertiesChanged
onCapabilitiesChanged
Is there a good implementation which we can use onCapabilitiesChanged to detect the current network capabilities?
Current Output : onAvailable not fired but the below events are fired.
onLinkPropertiesChanged
onCapabilitiesChanged
Is there a good implementation which we can use onCapabilitiesChanged to detect the current network capabilities?
ab...@gmail.com <ab...@gmail.com> #4
Actually onAvailable is fired. But immediately after that series of other events are fired which include onLost, Which programmatically speaking means that network is lost and not available. Even though internet is accessible. What was expected was onAvailable to be re-triggered after onLost, when connection was established.
This only happens when switching to wifi connection. When device is switched to cellular data, onLost is not triggered.
This is the debug log for when wifi is connected. This is attained by adding Log.d() on all the triggered events of `NetworkCallback()` class. Blank spaces are added to put a focus on "pause timings" of events fired.
2019-11-23 16:54:29.136 8416-8459/com.example.simplenetwork D/FLABS:: onAvailable
2019-11-23 16:54:29.136 8416-8459/com.example.simplenetwork D/FLABS:: onCapabilitiesChanged
2019-11-23 16:54:29.136 8416-8459/com.example.simplenetwork D/FLABS:: onLinkPropertiesChanged
2019-11-23 16:54:29.136 8416-8459/com.example.simplenetwork D/FLABS:: onBlockedStatusChanged
2019-11-23 16:54:29.307 8416-8459/com.example.simplenetwork D/FLABS:: onLosing
2019-11-23 16:54:29.325 8416-8459/com.example.simplenetwork D/FLABS:: onCapabilitiesChanged
2019-11-23 16:54:29.371 8416-8459/com.example.simplenetwork D/FLABS:: onLost
2019-11-23 16:54:29.959 8416-8459/com.example.simplenetwork D/FLABS:: onLinkPropertiesChanged
2019-11-23 16:54:29.975 8416-8459/com.example.simplenetwork D/FLABS:: onLinkPropertiesChanged
2019-11-23 16:54:30.972 8416-8459/com.example.simplenetwork D/FLABS:: onLinkPropertiesChanged
2019-11-23 16:54:31.693 8416-8459/com.example.simplenetwork D/FLABS:: onLinkPropertiesChanged
2019-11-23 16:54:32.053 8416-8459/com.example.simplenetwork D/FLABS:: onCapabilitiesChanged
Expected output,
onAvailable should be re-triggered once connection if properly established after handshake from wifi router/modem.
Current Output
After trigger of onLost, onAvailable is not triggered when onLinkPropertiesChanged and onCapabilitiesChanged is triggered.
My complete copy of code is available athttps://gist.github.com/Abhinav1217/0ff6b39e70fa38379d61e85e09b49fe7/
This only happens when switching to wifi connection. When device is switched to cellular data, onLost is not triggered.
This is the debug log for when wifi is connected. This is attained by adding Log.d() on all the triggered events of `NetworkCallback()` class. Blank spaces are added to put a focus on "pause timings" of events fired.
2019-11-23 16:54:29.136 8416-8459/com.example.simplenetwork D/FLABS:: onAvailable
2019-11-23 16:54:29.136 8416-8459/com.example.simplenetwork D/FLABS:: onCapabilitiesChanged
2019-11-23 16:54:29.136 8416-8459/com.example.simplenetwork D/FLABS:: onLinkPropertiesChanged
2019-11-23 16:54:29.136 8416-8459/com.example.simplenetwork D/FLABS:: onBlockedStatusChanged
2019-11-23 16:54:29.307 8416-8459/com.example.simplenetwork D/FLABS:: onLosing
2019-11-23 16:54:29.325 8416-8459/com.example.simplenetwork D/FLABS:: onCapabilitiesChanged
2019-11-23 16:54:29.371 8416-8459/com.example.simplenetwork D/FLABS:: onLost
2019-11-23 16:54:29.959 8416-8459/com.example.simplenetwork D/FLABS:: onLinkPropertiesChanged
2019-11-23 16:54:29.975 8416-8459/com.example.simplenetwork D/FLABS:: onLinkPropertiesChanged
2019-11-23 16:54:30.972 8416-8459/com.example.simplenetwork D/FLABS:: onLinkPropertiesChanged
2019-11-23 16:54:31.693 8416-8459/com.example.simplenetwork D/FLABS:: onLinkPropertiesChanged
2019-11-23 16:54:32.053 8416-8459/com.example.simplenetwork D/FLABS:: onCapabilitiesChanged
Expected output,
onAvailable should be re-triggered once connection if properly established after handshake from wifi router/modem.
Current Output
After trigger of onLost, onAvailable is not triggered when onLinkPropertiesChanged and onCapabilitiesChanged is triggered.
My complete copy of code is available at
vi...@google.com <vi...@google.com> #5
Response from the Engineering team:
===============================
Modern Android devices can connect to multiple networks at the same time. The NetworkCallback interface will tell you about all the networks that match the NetworkRequest you passed, and will pass the relevant Network as an argument. Keep in mind that there is no limit to how many networks a device can be connected : phones often are connected to both cellular and mobile at the same time, and some devices can connect to two WiFi networks at the same time for example.
In your code, you create a default NetworkRequest which will match all networks (except the restricted ones and VPNs). So this callback will be called for almost all networks, including cellular and WiFi as well as Ethernet or Bluetooth networks if present.
When the system calls your onAvailable(Network), it will pass the network that is available. When the system calls your onLost(Network), it will pass the network that was lost. So onLost() doesn't necessarily mean complete loss of connectivity, it means one network was lost, and the argument tells you which.
However your code ignores the Network argument. If you print it in the log, you'll see that the onLost was called for a different network. In practice, that means your code assumes loss of connectivity when any network at all is lost, even if some other good network is still connected.
In this case, when the device connects to WiFi, the Mobile network may stay connected or may disconnect if it's not needed. I suspect the onLost you are seeing when you connect to WiFi is the mobile network disconnecting as a result of being now unneeded, because the WiFi network is better.
When a network connects, your callback will get a call to onAvailable. To figure out what this network is capable of, wait for onCapabilitiesChanged, which is guaranteed to immediately come after onAvailable (as you already noticed). You can tell whether this is a mobile or a WiFi network by querying the NetworkCapabilities with hasTransport() and the appropriate transport constant (TRANSPORT_CELLULAR or TRANSPORT_WIFI for example).
Finally, you may want to take a look at ConnectivityManager#registerDefaultNetworkCallback. While registerNetworkCallback will send you information about all networks that match the request you pass, registerDefaultNetworkCallback will only tell you about the current default Internet network of the device. I suspect this is closer to what you seem to be interested in. Read the public documentation for details on how this works.
===============================
Modern Android devices can connect to multiple networks at the same time. The NetworkCallback interface will tell you about all the networks that match the NetworkRequest you passed, and will pass the relevant Network as an argument. Keep in mind that there is no limit to how many networks a device can be connected : phones often are connected to both cellular and mobile at the same time, and some devices can connect to two WiFi networks at the same time for example.
In your code, you create a default NetworkRequest which will match all networks (except the restricted ones and VPNs). So this callback will be called for almost all networks, including cellular and WiFi as well as Ethernet or Bluetooth networks if present.
When the system calls your onAvailable(Network), it will pass the network that is available. When the system calls your onLost(Network), it will pass the network that was lost. So onLost() doesn't necessarily mean complete loss of connectivity, it means one network was lost, and the argument tells you which.
However your code ignores the Network argument. If you print it in the log, you'll see that the onLost was called for a different network. In practice, that means your code assumes loss of connectivity when any network at all is lost, even if some other good network is still connected.
In this case, when the device connects to WiFi, the Mobile network may stay connected or may disconnect if it's not needed. I suspect the onLost you are seeing when you connect to WiFi is the mobile network disconnecting as a result of being now unneeded, because the WiFi network is better.
When a network connects, your callback will get a call to onAvailable. To figure out what this network is capable of, wait for onCapabilitiesChanged, which is guaranteed to immediately come after onAvailable (as you already noticed). You can tell whether this is a mobile or a WiFi network by querying the NetworkCapabilities with hasTransport() and the appropriate transport constant (TRANSPORT_CELLULAR or TRANSPORT_WIFI for example).
Finally, you may want to take a look at ConnectivityManager#registerDefaultNetworkCallback. While registerNetworkCallback will send you information about all networks that match the request you pass, registerDefaultNetworkCallback will only tell you about the current default Internet network of the device. I suspect this is closer to what you seem to be interested in. Read the public documentation for details on how this works.
pa...@gmail.com <pa...@gmail.com> #6
Thank you for the response. We'll give a try on your tip.
vi...@google.com <vi...@google.com> #7
Please let us know if you have followed comment #5 and got the clarification about this issue.
ab...@gmail.com <ab...@gmail.com> #8
Sorry for forgetting to reply on this.
The explanation was right on point, and easy to understand.
ConnectivityManager#registerDefaultNetworkCallback is exactly what I was looking for. It's only caveat is that it is available from API-24, while to achieve even 60% of devices(as reported by android studio), we must atleast support API-23, And in my company, some legacy enterprise app needs to be supported to API 17 atleast.
I have been playing with instructions about ConnectivityManager#registerNetworkCallback with onCapabilitiesChanged (which is better legacy supported), also taking points fromhttps://issuetracker.google.com/issues/135044193#comment4 . But haven't been able to fully perfect a solution. But that is not of any concern to this post.
My current solution is to use if-else block for checking API version 24 and use appropriate code block. I do plan to find a solution with "onCapabilitiesChanged" too since it has a better legacy support, and will eliminate any need for conditional block.
In the end, I want to send my thanks and regards to Engineering team for a simple to understand explanation on how this works. The API Docs, by design, are a bit too technically focused and misses out on such finer real world details.
You can close this issue from my end, since based on what I can understand from the explanation, this behavior was intended by design.
Regards
The explanation was right on point, and easy to understand.
ConnectivityManager#registerDefaultNetworkCallback is exactly what I was looking for. It's only caveat is that it is available from API-24, while to achieve even 60% of devices(as reported by android studio), we must atleast support API-23, And in my company, some legacy enterprise app needs to be supported to API 17 atleast.
I have been playing with instructions about ConnectivityManager#registerNetworkCallback with onCapabilitiesChanged (which is better legacy supported), also taking points from
My current solution is to use if-else block for checking API version 24 and use appropriate code block. I do plan to find a solution with "onCapabilitiesChanged" too since it has a better legacy support, and will eliminate any need for conditional block.
In the end, I want to send my thanks and regards to Engineering team for a simple to understand explanation on how this works. The API Docs, by design, are a bit too technically focused and misses out on such finer real world details.
You can close this issue from my end, since based on what I can understand from the explanation, this behavior was intended by design.
Regards
vi...@google.com <vi...@google.com>
su...@innocrux.com <su...@innocrux.com> #9
what is the fix for this issue?
ab...@gmail.com <ab...@gmail.com> #10
Take your pick.
https://gist.github.com/PasanBhanu/730a32a9eeb180ec2950c172d54bb06a
We are still using registerDefaultNetworkCallback as that is still a reasonably simple solution that does not have any dependencies. I would also suggest you to read the explanation given at comment 5 by google team, it will help you understand the actual process flow.
The gist I shared that originally tracked this issue, now contains a lot of contributions using many other libraries and alternate workflows.
We are still using registerDefaultNetworkCallback as that is still a reasonably simple solution that does not have any dependencies. I would also suggest you to read the explanation given at comment 5 by google team, it will help you understand the actual process flow.
The gist I shared that originally tracked this issue, now contains a lot of contributions using many other libraries and alternate workflows.
Description
public void registerNetworkCallback(Context context){
try {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkRequest.Builder builder = new NetworkRequest.Builder();
connectivityManager.registerNetworkCallback(builder.build(), new ConnectivityManager.NetworkCallback(){
@Override
public void onAvailable(@NonNull android.net.Network network) {
super.onAvailable(network);
GlobalVars.isNetworkConnected = true; // Static Global Boolean Variable
}
@Override
public void onLost(@NonNull android.net.Network network) {
super.onLost(network);
GlobalVars.isNetworkConnected = false; // Static Global Boolean Variable
}
});
} catch (Exception e) {
Log.d("FLABS:", " Exception in registerNetworkCallback");
GlobalVars.isNetworkConnected = false;
}
}
}
When device is connected to wifi ( from other network state like airplane mode or cellular data), onLost() is triggered after onAvailable() for some reason. Thus setting the global variable to false, even when there is active internet connection on the device. Since onCapabilitiesChanged() is called multiple times, using it to determine state of network is inefficient and unreliable.
2019-11-23 16:54:29.136 8416-8459/com.example.simplenetwork D/FLABS:: onAvailable
2019-11-23 16:54:29.136 8416-8459/com.example.simplenetwork D/FLABS:: onCapabilitiesChanged
2019-11-23 16:54:29.136 8416-8459/com.example.simplenetwork D/FLABS:: onLinkPropertiesChanged
2019-11-23 16:54:29.136 8416-8459/com.example.simplenetwork D/FLABS:: onBlockedStatusChanged
2019-11-23 16:54:29.307 8416-8459/com.example.simplenetwork D/FLABS:: onLosing
2019-11-23 16:54:29.325 8416-8459/com.example.simplenetwork D/FLABS:: onCapabilitiesChanged
2019-11-23 16:54:29.371 8416-8459/com.example.simplenetwork D/FLABS:: onLost
2019-11-23 16:54:29.959 8416-8459/com.example.simplenetwork D/FLABS:: onLinkPropertiesChanged
2019-11-23 16:54:29.975 8416-8459/com.example.simplenetwork D/FLABS:: onLinkPropertiesChanged
2019-11-23 16:54:30.972 8416-8459/com.example.simplenetwork D/FLABS:: onLinkPropertiesChanged
2019-11-23 16:54:31.693 8416-8459/com.example.simplenetwork D/FLABS:: onLinkPropertiesChanged
2019-11-23 16:54:32.053 8416-8459/com.example.simplenetwork D/FLABS:: onCapabilitiesChanged
I can assume onLost is triggered when router completes handshake and allows device to be connected(causing it to be momentarily disconnect and reconnect, But once final connection is established shouldn't onAvailable() be triggered.
You can check my discussion, and a detailed debug log on
You can also see my working copy of code on