NetworkCapabilities.java revision 4e2dea77dcaa0b7b940d881bbc25e13e35e2ea49
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.net; 18 19import android.os.Parcel; 20import android.os.Parcelable; 21import android.text.TextUtils; 22import java.lang.IllegalArgumentException; 23 24/** 25 * This class represents the capabilities of a network. This is used both to specify 26 * needs to {@link ConnectivityManager} and when inspecting a network. 27 * 28 * Note that this replaces the old {@link ConnectivityManager#TYPE_MOBILE} method 29 * of network selection. Rather than indicate a need for Wi-Fi because an application 30 * needs high bandwidth and risk obsolescence when a new, fast network appears (like LTE), 31 * the application should specify it needs high bandwidth. Similarly if an application 32 * needs an unmetered network for a bulk transfer it can specify that rather than assuming 33 * all cellular based connections are metered and all Wi-Fi based connections are not. 34 */ 35public final class NetworkCapabilities implements Parcelable { 36 /** 37 * @hide 38 */ 39 public NetworkCapabilities() { 40 } 41 42 public NetworkCapabilities(NetworkCapabilities nc) { 43 if (nc != null) { 44 mNetworkCapabilities = nc.mNetworkCapabilities; 45 mTransportTypes = nc.mTransportTypes; 46 mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps; 47 mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps; 48 mNetworkSpecifier = nc.mNetworkSpecifier; 49 } 50 } 51 52 /** 53 * Represents the network's capabilities. If any are specified they will be satisfied 54 * by any Network that matches all of them. 55 */ 56 private long mNetworkCapabilities = (1 << NET_CAPABILITY_NOT_RESTRICTED) | 57 (1 << NET_CAPABILITY_TRUSTED) | (1 << NET_CAPABILITY_NOT_VPN); 58 59 /** 60 * Indicates this is a network that has the ability to reach the 61 * carrier's MMSC for sending and receiving MMS messages. 62 */ 63 public static final int NET_CAPABILITY_MMS = 0; 64 65 /** 66 * Indicates this is a network that has the ability to reach the carrier's 67 * SUPL server, used to retrieve GPS information. 68 */ 69 public static final int NET_CAPABILITY_SUPL = 1; 70 71 /** 72 * Indicates this is a network that has the ability to reach the carrier's 73 * DUN or tethering gateway. 74 */ 75 public static final int NET_CAPABILITY_DUN = 2; 76 77 /** 78 * Indicates this is a network that has the ability to reach the carrier's 79 * FOTA portal, used for over the air updates. 80 */ 81 public static final int NET_CAPABILITY_FOTA = 3; 82 83 /** 84 * Indicates this is a network that has the ability to reach the carrier's 85 * IMS servers, used for network registration and signaling. 86 */ 87 public static final int NET_CAPABILITY_IMS = 4; 88 89 /** 90 * Indicates this is a network that has the ability to reach the carrier's 91 * CBS servers, used for carrier specific services. 92 */ 93 public static final int NET_CAPABILITY_CBS = 5; 94 95 /** 96 * Indicates this is a network that has the ability to reach a Wi-Fi direct 97 * peer. 98 */ 99 public static final int NET_CAPABILITY_WIFI_P2P = 6; 100 101 /** 102 * Indicates this is a network that has the ability to reach a carrier's 103 * Initial Attach servers. 104 */ 105 public static final int NET_CAPABILITY_IA = 7; 106 107 /** 108 * Indicates this is a network that has the ability to reach a carrier's 109 * RCS servers, used for Rich Communication Services. 110 */ 111 public static final int NET_CAPABILITY_RCS = 8; 112 113 /** 114 * Indicates this is a network that has the ability to reach a carrier's 115 * XCAP servers, used for configuration and control. 116 */ 117 public static final int NET_CAPABILITY_XCAP = 9; 118 119 /** 120 * Indicates this is a network that has the ability to reach a carrier's 121 * Emergency IMS servers, used for network signaling during emergency calls. 122 */ 123 public static final int NET_CAPABILITY_EIMS = 10; 124 125 /** 126 * Indicates that this network is unmetered. 127 */ 128 public static final int NET_CAPABILITY_NOT_METERED = 11; 129 130 /** 131 * Indicates that this network should be able to reach the internet. 132 */ 133 public static final int NET_CAPABILITY_INTERNET = 12; 134 135 /** 136 * Indicates that this network is available for general use. If this is not set 137 * applications should not attempt to communicate on this network. Note that this 138 * is simply informative and not enforcement - enforcement is handled via other means. 139 * Set by default. 140 */ 141 public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; 142 143 /** 144 * Indicates that the user has indicated implicit trust of this network. This 145 * generally means it's a sim-selected carrier, a plugged in ethernet, a paired 146 * BT device or a wifi the user asked to connect to. Untrusted networks 147 * are probably limited to unknown wifi AP. Set by default. 148 */ 149 public static final int NET_CAPABILITY_TRUSTED = 14; 150 151 /* 152 * Indicates that this network is not a VPN. This capability is set by default and should be 153 * explicitly cleared when creating VPN networks. 154 */ 155 public static final int NET_CAPABILITY_NOT_VPN = 15; 156 157 158 private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS; 159 private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_VPN; 160 161 /** 162 * Adds the given capability to this {@code NetworkCapability} instance. 163 * Multiple capabilities may be applied sequentially. Note that when searching 164 * for a network to satisfy a request, all capabilities requested must be satisfied. 165 * 166 * @param capability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be added. 167 * @return This NetworkCapability to facilitate chaining. 168 * @hide 169 */ 170 public NetworkCapabilities addCapability(int capability) { 171 if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) { 172 throw new IllegalArgumentException("NetworkCapability out of range"); 173 } 174 mNetworkCapabilities |= 1 << capability; 175 return this; 176 } 177 178 /** 179 * Removes (if found) the given capability from this {@code NetworkCapability} instance. 180 * 181 * @param capability the {@code NetworkCapabilities.NET_CAPABILTIY_*} to be removed. 182 * @return This NetworkCapability to facilitate chaining. 183 * @hide 184 */ 185 public NetworkCapabilities removeCapability(int capability) { 186 if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) { 187 throw new IllegalArgumentException("NetworkCapability out of range"); 188 } 189 mNetworkCapabilities &= ~(1 << capability); 190 return this; 191 } 192 193 /** 194 * Gets all the capabilities set on this {@code NetworkCapability} instance. 195 * 196 * @return an array of {@code NetworkCapabilities.NET_CAPABILITY_*} values 197 * for this instance. 198 * @hide 199 */ 200 public int[] getCapabilities() { 201 return enumerateBits(mNetworkCapabilities); 202 } 203 204 /** 205 * Tests for the presence of a capabilitity on this instance. 206 * 207 * @param capability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be tested for. 208 * @return {@code true} if set on this instance. 209 */ 210 public boolean hasCapability(int capability) { 211 if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) { 212 return false; 213 } 214 return ((mNetworkCapabilities & (1 << capability)) != 0); 215 } 216 217 private int[] enumerateBits(long val) { 218 int size = Long.bitCount(val); 219 int[] result = new int[size]; 220 int index = 0; 221 int resource = 0; 222 while (val > 0) { 223 if ((val & 1) == 1) result[index++] = resource; 224 val = val >> 1; 225 resource++; 226 } 227 return result; 228 } 229 230 private void combineNetCapabilities(NetworkCapabilities nc) { 231 this.mNetworkCapabilities |= nc.mNetworkCapabilities; 232 } 233 234 private boolean satisfiedByNetCapabilities(NetworkCapabilities nc) { 235 return ((nc.mNetworkCapabilities & this.mNetworkCapabilities) == this.mNetworkCapabilities); 236 } 237 238 private boolean equalsNetCapabilities(NetworkCapabilities nc) { 239 return (nc.mNetworkCapabilities == this.mNetworkCapabilities); 240 } 241 242 /** 243 * Representing the transport type. Apps should generally not care about transport. A 244 * request for a fast internet connection could be satisfied by a number of different 245 * transports. If any are specified here it will be satisfied a Network that matches 246 * any of them. If a caller doesn't care about the transport it should not specify any. 247 */ 248 private long mTransportTypes; 249 250 /** 251 * Indicates this network uses a Cellular transport. 252 */ 253 public static final int TRANSPORT_CELLULAR = 0; 254 255 /** 256 * Indicates this network uses a Wi-Fi transport. 257 */ 258 public static final int TRANSPORT_WIFI = 1; 259 260 /** 261 * Indicates this network uses a Bluetooth transport. 262 */ 263 public static final int TRANSPORT_BLUETOOTH = 2; 264 265 /** 266 * Indicates this network uses an Ethernet transport. 267 */ 268 public static final int TRANSPORT_ETHERNET = 3; 269 270 /** 271 * Indicates this network uses a VPN transport. 272 */ 273 public static final int TRANSPORT_VPN = 4; 274 275 private static final int MIN_TRANSPORT = TRANSPORT_CELLULAR; 276 private static final int MAX_TRANSPORT = TRANSPORT_VPN; 277 278 /** 279 * Adds the given transport type to this {@code NetworkCapability} instance. 280 * Multiple transports may be applied sequentially. Note that when searching 281 * for a network to satisfy a request, any listed in the request will satisfy the request. 282 * For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a 283 * {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network 284 * to be selected. This is logically different than 285 * {@code NetworkCapabilities.NET_CAPABILITY_*} listed above. 286 * 287 * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be added. 288 * @return This NetworkCapability to facilitate chaining. 289 * @hide 290 */ 291 public NetworkCapabilities addTransportType(int transportType) { 292 if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) { 293 throw new IllegalArgumentException("TransportType out of range"); 294 } 295 mTransportTypes |= 1 << transportType; 296 setNetworkSpecifier(mNetworkSpecifier); // used for exception checking 297 return this; 298 } 299 300 /** 301 * Removes (if found) the given transport from this {@code NetworkCapability} instance. 302 * 303 * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be removed. 304 * @return This NetworkCapability to facilitate chaining. 305 * @hide 306 */ 307 public NetworkCapabilities removeTransportType(int transportType) { 308 if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) { 309 throw new IllegalArgumentException("TransportType out of range"); 310 } 311 mTransportTypes &= ~(1 << transportType); 312 setNetworkSpecifier(mNetworkSpecifier); // used for exception checking 313 return this; 314 } 315 316 /** 317 * Gets all the transports set on this {@code NetworkCapability} instance. 318 * 319 * @return an array of {@code NetworkCapabilities.TRANSPORT_*} values 320 * for this instance. 321 * @hide 322 */ 323 public int[] getTransportTypes() { 324 return enumerateBits(mTransportTypes); 325 } 326 327 /** 328 * Tests for the presence of a transport on this instance. 329 * 330 * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be tested for. 331 * @return {@code true} if set on this instance. 332 */ 333 public boolean hasTransport(int transportType) { 334 if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) { 335 return false; 336 } 337 return ((mTransportTypes & (1 << transportType)) != 0); 338 } 339 340 private void combineTransportTypes(NetworkCapabilities nc) { 341 this.mTransportTypes |= nc.mTransportTypes; 342 } 343 private boolean satisfiedByTransportTypes(NetworkCapabilities nc) { 344 return ((this.mTransportTypes == 0) || 345 ((this.mTransportTypes & nc.mTransportTypes) != 0)); 346 } 347 private boolean equalsTransportTypes(NetworkCapabilities nc) { 348 return (nc.mTransportTypes == this.mTransportTypes); 349 } 350 351 /** 352 * Passive link bandwidth. This is a rough guide of the expected peak bandwidth 353 * for the first hop on the given transport. It is not measured, but may take into account 354 * link parameters (Radio technology, allocated channels, etc). 355 */ 356 private int mLinkUpBandwidthKbps; 357 private int mLinkDownBandwidthKbps; 358 359 /** 360 * Sets the upstream bandwidth for this network in Kbps. This always only refers to 361 * the estimated first hop transport bandwidth. 362 * <p> 363 * Note that when used to request a network, this specifies the minimum acceptable. 364 * When received as the state of an existing network this specifies the typical 365 * first hop bandwidth expected. This is never measured, but rather is inferred 366 * from technology type and other link parameters. It could be used to differentiate 367 * between very slow 1xRTT cellular links and other faster networks or even between 368 * 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between 369 * fast backhauls and slow backhauls. 370 * 371 * @param upKbps the estimated first hop upstream (device to network) bandwidth. 372 * @hide 373 */ 374 public void setLinkUpstreamBandwidthKbps(int upKbps) { 375 mLinkUpBandwidthKbps = upKbps; 376 } 377 378 /** 379 * Retrieves the upstream bandwidth for this network in Kbps. This always only refers to 380 * the estimated first hop transport bandwidth. 381 * 382 * @return The estimated first hop upstream (device to network) bandwidth. 383 */ 384 public int getLinkUpstreamBandwidthKbps() { 385 return mLinkUpBandwidthKbps; 386 } 387 388 /** 389 * Sets the downstream bandwidth for this network in Kbps. This always only refers to 390 * the estimated first hop transport bandwidth. 391 * <p> 392 * Note that when used to request a network, this specifies the minimum acceptable. 393 * When received as the state of an existing network this specifies the typical 394 * first hop bandwidth expected. This is never measured, but rather is inferred 395 * from technology type and other link parameters. It could be used to differentiate 396 * between very slow 1xRTT cellular links and other faster networks or even between 397 * 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between 398 * fast backhauls and slow backhauls. 399 * 400 * @param downKbps the estimated first hop downstream (network to device) bandwidth. 401 * @hide 402 */ 403 public void setLinkDownstreamBandwidthKbps(int downKbps) { 404 mLinkDownBandwidthKbps = downKbps; 405 } 406 407 /** 408 * Retrieves the downstream bandwidth for this network in Kbps. This always only refers to 409 * the estimated first hop transport bandwidth. 410 * 411 * @return The estimated first hop downstream (network to device) bandwidth. 412 */ 413 public int getLinkDownstreamBandwidthKbps() { 414 return mLinkDownBandwidthKbps; 415 } 416 417 private void combineLinkBandwidths(NetworkCapabilities nc) { 418 this.mLinkUpBandwidthKbps = 419 Math.max(this.mLinkUpBandwidthKbps, nc.mLinkUpBandwidthKbps); 420 this.mLinkDownBandwidthKbps = 421 Math.max(this.mLinkDownBandwidthKbps, nc.mLinkDownBandwidthKbps); 422 } 423 private boolean satisfiedByLinkBandwidths(NetworkCapabilities nc) { 424 return !(this.mLinkUpBandwidthKbps > nc.mLinkUpBandwidthKbps || 425 this.mLinkDownBandwidthKbps > nc.mLinkDownBandwidthKbps); 426 } 427 private boolean equalsLinkBandwidths(NetworkCapabilities nc) { 428 return (this.mLinkUpBandwidthKbps == nc.mLinkUpBandwidthKbps && 429 this.mLinkDownBandwidthKbps == nc.mLinkDownBandwidthKbps); 430 } 431 432 private String mNetworkSpecifier; 433 /** 434 * Sets the optional bearer specific network specifier. 435 * This has no meaning if a single transport is also not specified, so calling 436 * this without a single transport set will generate an exception, as will 437 * subsequently adding or removing transports after this is set. 438 * </p> 439 * The interpretation of this {@code String} is bearer specific and bearers that use 440 * it should document their particulars. For example, Bluetooth may use some sort of 441 * device id while WiFi could used SSID and/or BSSID. Cellular may use carrier SPN (name) 442 * or Subscription ID. 443 * 444 * @param networkSpecifier An {@code String} of opaque format used to specify the bearer 445 * specific network specifier where the bearer has a choice of 446 * networks. 447 * @hide 448 */ 449 public void setNetworkSpecifier(String networkSpecifier) { 450 if (TextUtils.isEmpty(networkSpecifier) == false && Long.bitCount(mTransportTypes) != 1) { 451 throw new IllegalStateException("Must have a single transport specified to use " + 452 "setNetworkSpecifier"); 453 } 454 mNetworkSpecifier = networkSpecifier; 455 } 456 457 /** 458 * Gets the optional bearer specific network specifier. 459 * 460 * @return The optional {@code String} specifying the bearer specific network specifier. 461 * See {@link #setNetworkSpecifier}. 462 * @hide 463 */ 464 public String getNetworkSpecifier() { 465 return mNetworkSpecifier; 466 } 467 468 private void combineSpecifiers(NetworkCapabilities nc) { 469 String otherSpecifier = nc.getNetworkSpecifier(); 470 if (TextUtils.isEmpty(otherSpecifier)) return; 471 if (TextUtils.isEmpty(mNetworkSpecifier) == false) { 472 throw new IllegalStateException("Can't combine two networkSpecifiers"); 473 } 474 setNetworkSpecifier(otherSpecifier); 475 } 476 private boolean satisfiedBySpecifier(NetworkCapabilities nc) { 477 return (TextUtils.isEmpty(mNetworkSpecifier) || 478 mNetworkSpecifier.equals(nc.mNetworkSpecifier)); 479 } 480 private boolean equalsSpecifier(NetworkCapabilities nc) { 481 if (TextUtils.isEmpty(mNetworkSpecifier)) { 482 return TextUtils.isEmpty(nc.mNetworkSpecifier); 483 } else { 484 return mNetworkSpecifier.equals(nc.mNetworkSpecifier); 485 } 486 } 487 488 /** 489 * Combine a set of Capabilities to this one. Useful for coming up with the complete set 490 * {@hide} 491 */ 492 public void combineCapabilities(NetworkCapabilities nc) { 493 combineNetCapabilities(nc); 494 combineTransportTypes(nc); 495 combineLinkBandwidths(nc); 496 combineSpecifiers(nc); 497 } 498 499 /** 500 * Check if our requirements are satisfied by the given Capabilities. 501 * {@hide} 502 */ 503 public boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc) { 504 return (nc != null && 505 satisfiedByNetCapabilities(nc) && 506 satisfiedByTransportTypes(nc) && 507 satisfiedByLinkBandwidths(nc) && 508 satisfiedBySpecifier(nc)); 509 } 510 511 @Override 512 public boolean equals(Object obj) { 513 if (obj == null || (obj instanceof NetworkCapabilities == false)) return false; 514 NetworkCapabilities that = (NetworkCapabilities)obj; 515 return (equalsNetCapabilities(that) && 516 equalsTransportTypes(that) && 517 equalsLinkBandwidths(that) && 518 equalsSpecifier(that)); 519 } 520 521 @Override 522 public int hashCode() { 523 return ((int)(mNetworkCapabilities & 0xFFFFFFFF) + 524 ((int)(mNetworkCapabilities >> 32) * 3) + 525 ((int)(mTransportTypes & 0xFFFFFFFF) * 5) + 526 ((int)(mTransportTypes >> 32) * 7) + 527 (mLinkUpBandwidthKbps * 11) + 528 (mLinkDownBandwidthKbps * 13) + 529 (TextUtils.isEmpty(mNetworkSpecifier) ? 0 : mNetworkSpecifier.hashCode() * 17)); 530 } 531 532 @Override 533 public int describeContents() { 534 return 0; 535 } 536 @Override 537 public void writeToParcel(Parcel dest, int flags) { 538 dest.writeLong(mNetworkCapabilities); 539 dest.writeLong(mTransportTypes); 540 dest.writeInt(mLinkUpBandwidthKbps); 541 dest.writeInt(mLinkDownBandwidthKbps); 542 dest.writeString(mNetworkSpecifier); 543 } 544 public static final Creator<NetworkCapabilities> CREATOR = 545 new Creator<NetworkCapabilities>() { 546 @Override 547 public NetworkCapabilities createFromParcel(Parcel in) { 548 NetworkCapabilities netCap = new NetworkCapabilities(); 549 550 netCap.mNetworkCapabilities = in.readLong(); 551 netCap.mTransportTypes = in.readLong(); 552 netCap.mLinkUpBandwidthKbps = in.readInt(); 553 netCap.mLinkDownBandwidthKbps = in.readInt(); 554 netCap.mNetworkSpecifier = in.readString(); 555 return netCap; 556 } 557 @Override 558 public NetworkCapabilities[] newArray(int size) { 559 return new NetworkCapabilities[size]; 560 } 561 }; 562 563 @Override 564 public String toString() { 565 int[] types = getTransportTypes(); 566 String transports = (types.length > 0 ? " Transports: " : ""); 567 for (int i = 0; i < types.length;) { 568 switch (types[i]) { 569 case TRANSPORT_CELLULAR: transports += "CELLULAR"; break; 570 case TRANSPORT_WIFI: transports += "WIFI"; break; 571 case TRANSPORT_BLUETOOTH: transports += "BLUETOOTH"; break; 572 case TRANSPORT_ETHERNET: transports += "ETHERNET"; break; 573 case TRANSPORT_VPN: transports += "VPN"; break; 574 } 575 if (++i < types.length) transports += "|"; 576 } 577 578 types = getCapabilities(); 579 String capabilities = (types.length > 0 ? " Capabilities: " : ""); 580 for (int i = 0; i < types.length; ) { 581 switch (types[i]) { 582 case NET_CAPABILITY_MMS: capabilities += "MMS"; break; 583 case NET_CAPABILITY_SUPL: capabilities += "SUPL"; break; 584 case NET_CAPABILITY_DUN: capabilities += "DUN"; break; 585 case NET_CAPABILITY_FOTA: capabilities += "FOTA"; break; 586 case NET_CAPABILITY_IMS: capabilities += "IMS"; break; 587 case NET_CAPABILITY_CBS: capabilities += "CBS"; break; 588 case NET_CAPABILITY_WIFI_P2P: capabilities += "WIFI_P2P"; break; 589 case NET_CAPABILITY_IA: capabilities += "IA"; break; 590 case NET_CAPABILITY_RCS: capabilities += "RCS"; break; 591 case NET_CAPABILITY_XCAP: capabilities += "XCAP"; break; 592 case NET_CAPABILITY_EIMS: capabilities += "EIMS"; break; 593 case NET_CAPABILITY_NOT_METERED: capabilities += "NOT_METERED"; break; 594 case NET_CAPABILITY_INTERNET: capabilities += "INTERNET"; break; 595 case NET_CAPABILITY_NOT_RESTRICTED: capabilities += "NOT_RESTRICTED"; break; 596 case NET_CAPABILITY_TRUSTED: capabilities += "TRUSTED"; break; 597 case NET_CAPABILITY_NOT_VPN: capabilities += "NOT_VPN"; break; 598 } 599 if (++i < types.length) capabilities += "&"; 600 } 601 602 String upBand = ((mLinkUpBandwidthKbps > 0) ? " LinkUpBandwidth>=" + 603 mLinkUpBandwidthKbps + "Kbps" : ""); 604 String dnBand = ((mLinkDownBandwidthKbps > 0) ? " LinkDnBandwidth>=" + 605 mLinkDownBandwidthKbps + "Kbps" : ""); 606 607 String specifier = (mNetworkSpecifier == null ? 608 "" : " Specifier: <" + mNetworkSpecifier + ">"); 609 610 return "[" + transports + capabilities + upBand + dnBand + specifier + "]"; 611 } 612} 613