I'm tying to get imformation from getLinkDownstreamBandwidthKbps()
, getLinkUpstreamBandwidthKbps()
and getSignalStrength()
of NetworkCapabilities
class.
For this I do the following in MainActivity
:
private static ConnectivityManager connectivityManager;
...
@Override
protected void onCreate(final Bundle savedInstanceState) {
connectivityManager = (ConnectivityManager) context.getSystemService(CONNECTIVITY_SERVICE);
}
private final NetworkRequest networkRequest = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build();
private final NetworkCallback networkCallback = new NetworkCallback() {
@Override
public void onCapabilitiesChanged(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
int dLBandwidth = networkCapabilities.getLinkDownstreamBandwidthKbps();
int uLBandwidth = networkCapabilities.getLinkUpstreamBandwidthKbps();
int signalStrength = networkCapabilities.getSignalStrength();
final String timestamp = Util.getCurrentTimestamp();
Util.log(String.format(Locale.US, "CM::%s::dLBandwidth=%d::uLBandwidth=%d::sStrength=%d\n",
timestamp, dLBandwidth, uLBandwidth, signalStrength));
}
};
private View getStartButton() { // button click handler
connectivityManager.registerNetworkCallback(networkRequest, networkCallback);
}
private View getStopButton() { // button click handler
connectivityManager.unregisterNetworkCallback(networkCallback);
}
By some reason I get only one entry in log.
CM::2023-09-17 13:11:07.882::dLBandwidth=30000::uLBandwidth=15000::sStrength=-2147483648
So, NetworkCallback
is called only once, although I'm moving with the phone around the home so that the signal strength changes.
Could somebody advise what the reason of such behaviour? What I'm doing wrong?
In my case minSdkVersion 29
, compileSdk 33
.
Thanks!
It looks like such behaviour is predictable.
SignalStrength
== -2147483648
== Integer.MIN_VALUE
== SIGNAL_STRENGTH_UNSPECIFIED.According to documentation it means the following:
Magic value that indicates no signal strength provided. A request specifying this value is always satisfied.
Constant Value: -2147483648 (0x80000000)
/**
* Magic value that indicates no signal strength provided. A request specifying this value is
* always satisfied.
*/
public static final int SIGNAL_STRENGTH_UNSPECIFIED = Integer.MIN_VALUE;
So, it looks like in my case signal strength is not provided.
LinkDownstreamBandwidth
== 30000
and LinkUpstreamBandwidth
== 15000
.In my case I get these magic numbers and they are never updated. If we trace the sequence of calls of setters for these values we get the following sequence:
setLinkDownstreamBandwidthKbps:3013
/**
* Sets the downstream bandwidth for this network in Kbps. This always only refers to
* the estimated first hop transport bandwidth.
* <p>
* Note that when used to request a network, this specifies the minimum acceptable.
* When received as the state of an existing network this specifies the typical
* first hop bandwidth expected. This is never measured, but rather is inferred
* from technology type and other link parameters. It could be used to differentiate
* between very slow 1xRTT cellular links and other faster networks or even between
* 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between
* fast backhauls and slow backhauls.
*
* @param downKbps the estimated first hop downstream (network to device) bandwidth.
* @return this builder
*/
@NonNull
public Builder setLinkDownstreamBandwidthKbps(final int downKbps) {
mCaps.setLinkDownstreamBandwidthKbps(downKbps);
return this;
}
updateNetworkCapabilities:2080
/**
* Update the network capabilities.
*/
private void updateNetworkCapabilities() {
final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
boolean roaming = mPhone.getServiceState().getDataRoaming();
...
// Set the bandwidth information.
builder.setLinkDownstreamBandwidthKbps(mNetworkBandwidth.downlinkBandwidthKbps); <---
builder.setLinkUpstreamBandwidthKbps(mNetworkBandwidth.uplinkBandwidthKbps); <---
...
}
/**
* The network bandwidth.
*/
public static class NetworkBandwidth {
/** The downlink bandwidth in Kbps. */
public final int downlinkBandwidthKbps;
/** The uplink Bandwidth in Kbps. */
public final int uplinkBandwidthKbps;
/**
* Constructor.
*
* @param downlinkBandwidthKbps The downlink bandwidth in Kbps.
* @param uplinkBandwidthKbps The uplink Bandwidth in Kbps.
*/
public NetworkBandwidth(int downlinkBandwidthKbps, int uplinkBandwidthKbps) { <---
this.downlinkBandwidthKbps = downlinkBandwidthKbps;
this.uplinkBandwidthKbps = uplinkBandwidthKbps;
}
@Override
public String toString() {
return String.format("NetworkBandwidth=[downlink=%d, uplink=%d]",
downlinkBandwidthKbps, uplinkBandwidthKbps);
}
}
/**
* Update the downlink and uplink bandwidth values from the carrier config.
*/
private void updateBandwidths() {
synchronized (this) {
mBandwidthMap.clear();
String[] bandwidths = mCarrierConfig.getStringArray(
CarrierConfigManager.KEY_BANDWIDTH_STRING_ARRAY); <---
boolean useLte = mCarrierConfig.getBoolean(CarrierConfigManager
.KEY_BANDWIDTH_NR_NSA_USE_LTE_VALUE_FOR_UPLINK_BOOL);
if (bandwidths != null) {
for (String bandwidth : bandwidths) {
// split1[0] = network type as string
// split1[1] = downlink,uplink
String[] split1 = bandwidth.split(":");
if (split1.length != 2) {
loge("Invalid bandwidth: " + bandwidth);
continue;
}
// split2[0] = downlink bandwidth in kbps
// split2[1] = uplink bandwidth in kbps
String[] split2 = split1[1].split(",");
if (split2.length != 2) {
loge("Invalid bandwidth values: " + Arrays.toString(split2));
continue;
}
int downlink, uplink;
try {
downlink = Integer.parseInt(split2[0]);
uplink = Integer.parseInt(split2[1]);
} catch (NumberFormatException e) {
loge("Exception parsing bandwidth values for network type " + split1[0]
+ ": " + e);
continue;
}
if (useLte && split1[0].startsWith("NR")) {
// We can get it directly from mBandwidthMap because LTE is defined before
// the NR values in CarrierConfigManager#KEY_BANDWIDTH_STRING_ARRAY.
uplink = mBandwidthMap.get(DATA_CONFIG_NETWORK_TYPE_LTE)
.uplinkBandwidthKbps;
}
mBandwidthMap.put(split1[0],
new DataNetwork.NetworkBandwidth(downlink, uplink));
}
}
}
}
KEY_BANDWIDTH_STRING_ARRAY:2996
/**
* String array of default bandwidth values per network type.
* The entries should be of form: "network_name:downlink,uplink", with values in Kbps.
* For NR (5G), the following network names should be used:
* - NR_NSA: NR NSA, sub-6 frequencies
* - NR_NSA_MMWAVE: NR NSA, mmwave frequencies
* - NR_SA: NR SA, sub-6 frequencies
* - NR_SA_MMWAVE: NR SA, mmwave frequencies
* @hide
*/
public static final String KEY_BANDWIDTH_STRING_ARRAY = "bandwidth_string_array";
sDefaults.putStringArray(KEY_BANDWIDTH_STRING_ARRAY, new String[]{
"GPRS:24,24", "EDGE:70,18", "UMTS:115,115", "CDMA:14,14",
"1xRTT:30,30", "EvDo_0:750,48", "EvDo_A:950,550", "HSDPA:4300,620",
"HSUPA:4300,1800", "HSPA:4300,1800", "EvDo_B:1500,550", "eHRPD:750,48",
"iDEN:14,14", "LTE:30000,15000", "HSPA+:13000,3400", "GSM:24,24",
"TD_SCDMA:115,115", "LTE_CA:30000,15000", "NR_NSA:47000,18000",
"NR_NSA_MMWAVE:145000,60000", "NR_SA:145000,60000", "NR_SA_MMWAVE:145000,60000"});
So, I can assume for devices which I used for test I can get only default values for CELLULAR
transport type. Perhaps modem firmware/driver doesn't expose such data.
In the same time this API provides correct values for WIFI
transport type.