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 17 package android.net; 18 19 import android.os.Parcel; 20 import android.os.Parcelable; 21 import android.text.TextUtils; 22 import 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 */ 35 public 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 * Indicates that connectivity on this network was successfully validated. For example, for a 159 * network with NET_CAPABILITY_INTERNET, it means that Internet connectivity was successfully 160 * detected. 161 * @hide 162 */ 163 public static final int NET_CAPABILITY_VALIDATED = 16; 164 165 private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS; 166 private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_VALIDATED; 167 168 /** 169 * Adds the given capability to this {@code NetworkCapability} instance. 170 * Multiple capabilities may be applied sequentially. Note that when searching 171 * for a network to satisfy a request, all capabilities requested must be satisfied. 172 * 173 * @param capability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be added. 174 * @return This NetworkCapability to facilitate chaining. 175 * @hide 176 */ 177 public NetworkCapabilities addCapability(int capability) { 178 if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) { 179 throw new IllegalArgumentException("NetworkCapability out of range"); 180 } 181 mNetworkCapabilities |= 1 << capability; 182 return this; 183 } 184 185 /** 186 * Removes (if found) the given capability from this {@code NetworkCapability} instance. 187 * 188 * @param capability the {@code NetworkCapabilities.NET_CAPABILTIY_*} to be removed. 189 * @return This NetworkCapability to facilitate chaining. 190 * @hide 191 */ 192 public NetworkCapabilities removeCapability(int capability) { 193 if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) { 194 throw new IllegalArgumentException("NetworkCapability out of range"); 195 } 196 mNetworkCapabilities &= ~(1 << capability); 197 return this; 198 } 199 200 /** 201 * Gets all the capabilities set on this {@code NetworkCapability} instance. 202 * 203 * @return an array of {@code NetworkCapabilities.NET_CAPABILITY_*} values 204 * for this instance. 205 * @hide 206 */ 207 public int[] getCapabilities() { 208 return enumerateBits(mNetworkCapabilities); 209 } 210 211 /** 212 * Tests for the presence of a capabilitity on this instance. 213 * 214 * @param capability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be tested for. 215 * @return {@code true} if set on this instance. 216 */ 217 public boolean hasCapability(int capability) { 218 if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) { 219 return false; 220 } 221 return ((mNetworkCapabilities & (1 << capability)) != 0); 222 } 223 224 private int[] enumerateBits(long val) { 225 int size = Long.bitCount(val); 226 int[] result = new int[size]; 227 int index = 0; 228 int resource = 0; 229 while (val > 0) { 230 if ((val & 1) == 1) result[index++] = resource; 231 val = val >> 1; 232 resource++; 233 } 234 return result; 235 } 236 237 private void combineNetCapabilities(NetworkCapabilities nc) { 238 this.mNetworkCapabilities |= nc.mNetworkCapabilities; 239 } 240 241 private boolean satisfiedByNetCapabilities(NetworkCapabilities nc) { 242 return ((nc.mNetworkCapabilities & this.mNetworkCapabilities) == this.mNetworkCapabilities); 243 } 244 245 /** @hide */ 246 public boolean equalsNetCapabilities(NetworkCapabilities nc) { 247 return (nc.mNetworkCapabilities == this.mNetworkCapabilities); 248 } 249 250 /** 251 * Representing the transport type. Apps should generally not care about transport. A 252 * request for a fast internet connection could be satisfied by a number of different 253 * transports. If any are specified here it will be satisfied a Network that matches 254 * any of them. If a caller doesn't care about the transport it should not specify any. 255 */ 256 private long mTransportTypes; 257 258 /** 259 * Indicates this network uses a Cellular transport. 260 */ 261 public static final int TRANSPORT_CELLULAR = 0; 262 263 /** 264 * Indicates this network uses a Wi-Fi transport. 265 */ 266 public static final int TRANSPORT_WIFI = 1; 267 268 /** 269 * Indicates this network uses a Bluetooth transport. 270 */ 271 public static final int TRANSPORT_BLUETOOTH = 2; 272 273 /** 274 * Indicates this network uses an Ethernet transport. 275 */ 276 public static final int TRANSPORT_ETHERNET = 3; 277 278 /** 279 * Indicates this network uses a VPN transport. 280 */ 281 public static final int TRANSPORT_VPN = 4; 282 283 private static final int MIN_TRANSPORT = TRANSPORT_CELLULAR; 284 private static final int MAX_TRANSPORT = TRANSPORT_VPN; 285 286 /** 287 * Adds the given transport type to this {@code NetworkCapability} instance. 288 * Multiple transports may be applied sequentially. Note that when searching 289 * for a network to satisfy a request, any listed in the request will satisfy the request. 290 * For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a 291 * {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network 292 * to be selected. This is logically different than 293 * {@code NetworkCapabilities.NET_CAPABILITY_*} listed above. 294 * 295 * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be added. 296 * @return This NetworkCapability to facilitate chaining. 297 * @hide 298 */ 299 public NetworkCapabilities addTransportType(int transportType) { 300 if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) { 301 throw new IllegalArgumentException("TransportType out of range"); 302 } 303 mTransportTypes |= 1 << transportType; 304 setNetworkSpecifier(mNetworkSpecifier); // used for exception checking 305 return this; 306 } 307 308 /** 309 * Removes (if found) the given transport from this {@code NetworkCapability} instance. 310 * 311 * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be removed. 312 * @return This NetworkCapability to facilitate chaining. 313 * @hide 314 */ 315 public NetworkCapabilities removeTransportType(int transportType) { 316 if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) { 317 throw new IllegalArgumentException("TransportType out of range"); 318 } 319 mTransportTypes &= ~(1 << transportType); 320 setNetworkSpecifier(mNetworkSpecifier); // used for exception checking 321 return this; 322 } 323 324 /** 325 * Gets all the transports set on this {@code NetworkCapability} instance. 326 * 327 * @return an array of {@code NetworkCapabilities.TRANSPORT_*} values 328 * for this instance. 329 * @hide 330 */ 331 public int[] getTransportTypes() { 332 return enumerateBits(mTransportTypes); 333 } 334 335 /** 336 * Tests for the presence of a transport on this instance. 337 * 338 * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be tested for. 339 * @return {@code true} if set on this instance. 340 */ 341 public boolean hasTransport(int transportType) { 342 if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) { 343 return false; 344 } 345 return ((mTransportTypes & (1 << transportType)) != 0); 346 } 347 348 private void combineTransportTypes(NetworkCapabilities nc) { 349 this.mTransportTypes |= nc.mTransportTypes; 350 } 351 private boolean satisfiedByTransportTypes(NetworkCapabilities nc) { 352 return ((this.mTransportTypes == 0) || 353 ((this.mTransportTypes & nc.mTransportTypes) != 0)); 354 } 355 /** @hide */ 356 public boolean equalsTransportTypes(NetworkCapabilities nc) { 357 return (nc.mTransportTypes == this.mTransportTypes); 358 } 359 360 /** 361 * Passive link bandwidth. This is a rough guide of the expected peak bandwidth 362 * for the first hop on the given transport. It is not measured, but may take into account 363 * link parameters (Radio technology, allocated channels, etc). 364 */ 365 private int mLinkUpBandwidthKbps; 366 private int mLinkDownBandwidthKbps; 367 368 /** 369 * Sets the upstream bandwidth for this network in Kbps. This always only refers to 370 * the estimated first hop transport bandwidth. 371 * <p> 372 * Note that when used to request a network, this specifies the minimum acceptable. 373 * When received as the state of an existing network this specifies the typical 374 * first hop bandwidth expected. This is never measured, but rather is inferred 375 * from technology type and other link parameters. It could be used to differentiate 376 * between very slow 1xRTT cellular links and other faster networks or even between 377 * 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between 378 * fast backhauls and slow backhauls. 379 * 380 * @param upKbps the estimated first hop upstream (device to network) bandwidth. 381 * @hide 382 */ 383 public void setLinkUpstreamBandwidthKbps(int upKbps) { 384 mLinkUpBandwidthKbps = upKbps; 385 } 386 387 /** 388 * Retrieves the upstream bandwidth for this network in Kbps. This always only refers to 389 * the estimated first hop transport bandwidth. 390 * 391 * @return The estimated first hop upstream (device to network) bandwidth. 392 */ 393 public int getLinkUpstreamBandwidthKbps() { 394 return mLinkUpBandwidthKbps; 395 } 396 397 /** 398 * Sets the downstream bandwidth for this network in Kbps. This always only refers to 399 * the estimated first hop transport bandwidth. 400 * <p> 401 * Note that when used to request a network, this specifies the minimum acceptable. 402 * When received as the state of an existing network this specifies the typical 403 * first hop bandwidth expected. This is never measured, but rather is inferred 404 * from technology type and other link parameters. It could be used to differentiate 405 * between very slow 1xRTT cellular links and other faster networks or even between 406 * 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between 407 * fast backhauls and slow backhauls. 408 * 409 * @param downKbps the estimated first hop downstream (network to device) bandwidth. 410 * @hide 411 */ 412 public void setLinkDownstreamBandwidthKbps(int downKbps) { 413 mLinkDownBandwidthKbps = downKbps; 414 } 415 416 /** 417 * Retrieves the downstream bandwidth for this network in Kbps. This always only refers to 418 * the estimated first hop transport bandwidth. 419 * 420 * @return The estimated first hop downstream (network to device) bandwidth. 421 */ 422 public int getLinkDownstreamBandwidthKbps() { 423 return mLinkDownBandwidthKbps; 424 } 425 426 private void combineLinkBandwidths(NetworkCapabilities nc) { 427 this.mLinkUpBandwidthKbps = 428 Math.max(this.mLinkUpBandwidthKbps, nc.mLinkUpBandwidthKbps); 429 this.mLinkDownBandwidthKbps = 430 Math.max(this.mLinkDownBandwidthKbps, nc.mLinkDownBandwidthKbps); 431 } 432 private boolean satisfiedByLinkBandwidths(NetworkCapabilities nc) { 433 return !(this.mLinkUpBandwidthKbps > nc.mLinkUpBandwidthKbps || 434 this.mLinkDownBandwidthKbps > nc.mLinkDownBandwidthKbps); 435 } 436 private boolean equalsLinkBandwidths(NetworkCapabilities nc) { 437 return (this.mLinkUpBandwidthKbps == nc.mLinkUpBandwidthKbps && 438 this.mLinkDownBandwidthKbps == nc.mLinkDownBandwidthKbps); 439 } 440 441 private String mNetworkSpecifier; 442 /** 443 * Sets the optional bearer specific network specifier. 444 * This has no meaning if a single transport is also not specified, so calling 445 * this without a single transport set will generate an exception, as will 446 * subsequently adding or removing transports after this is set. 447 * </p> 448 * The interpretation of this {@code String} is bearer specific and bearers that use 449 * it should document their particulars. For example, Bluetooth may use some sort of 450 * device id while WiFi could used SSID and/or BSSID. Cellular may use carrier SPN (name) 451 * or Subscription ID. 452 * 453 * @param networkSpecifier An {@code String} of opaque format used to specify the bearer 454 * specific network specifier where the bearer has a choice of 455 * networks. 456 * @hide 457 */ 458 public void setNetworkSpecifier(String networkSpecifier) { 459 if (TextUtils.isEmpty(networkSpecifier) == false && Long.bitCount(mTransportTypes) != 1) { 460 throw new IllegalStateException("Must have a single transport specified to use " + 461 "setNetworkSpecifier"); 462 } 463 mNetworkSpecifier = networkSpecifier; 464 } 465 466 /** 467 * Gets the optional bearer specific network specifier. 468 * 469 * @return The optional {@code String} specifying the bearer specific network specifier. 470 * See {@link #setNetworkSpecifier}. 471 * @hide 472 */ 473 public String getNetworkSpecifier() { 474 return mNetworkSpecifier; 475 } 476 477 private void combineSpecifiers(NetworkCapabilities nc) { 478 String otherSpecifier = nc.getNetworkSpecifier(); 479 if (TextUtils.isEmpty(otherSpecifier)) return; 480 if (TextUtils.isEmpty(mNetworkSpecifier) == false) { 481 throw new IllegalStateException("Can't combine two networkSpecifiers"); 482 } 483 setNetworkSpecifier(otherSpecifier); 484 } 485 private boolean satisfiedBySpecifier(NetworkCapabilities nc) { 486 return (TextUtils.isEmpty(mNetworkSpecifier) || 487 mNetworkSpecifier.equals(nc.mNetworkSpecifier)); 488 } 489 private boolean equalsSpecifier(NetworkCapabilities nc) { 490 if (TextUtils.isEmpty(mNetworkSpecifier)) { 491 return TextUtils.isEmpty(nc.mNetworkSpecifier); 492 } else { 493 return mNetworkSpecifier.equals(nc.mNetworkSpecifier); 494 } 495 } 496 497 /** 498 * Combine a set of Capabilities to this one. Useful for coming up with the complete set 499 * {@hide} 500 */ 501 public void combineCapabilities(NetworkCapabilities nc) { 502 combineNetCapabilities(nc); 503 combineTransportTypes(nc); 504 combineLinkBandwidths(nc); 505 combineSpecifiers(nc); 506 } 507 508 /** 509 * Check if our requirements are satisfied by the given Capabilities. 510 * {@hide} 511 */ 512 public boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc) { 513 return (nc != null && 514 satisfiedByNetCapabilities(nc) && 515 satisfiedByTransportTypes(nc) && 516 satisfiedByLinkBandwidths(nc) && 517 satisfiedBySpecifier(nc)); 518 } 519 520 @Override 521 public boolean equals(Object obj) { 522 if (obj == null || (obj instanceof NetworkCapabilities == false)) return false; 523 NetworkCapabilities that = (NetworkCapabilities)obj; 524 return (equalsNetCapabilities(that) && 525 equalsTransportTypes(that) && 526 equalsLinkBandwidths(that) && 527 equalsSpecifier(that)); 528 } 529 530 @Override 531 public int hashCode() { 532 return ((int)(mNetworkCapabilities & 0xFFFFFFFF) + 533 ((int)(mNetworkCapabilities >> 32) * 3) + 534 ((int)(mTransportTypes & 0xFFFFFFFF) * 5) + 535 ((int)(mTransportTypes >> 32) * 7) + 536 (mLinkUpBandwidthKbps * 11) + 537 (mLinkDownBandwidthKbps * 13) + 538 (TextUtils.isEmpty(mNetworkSpecifier) ? 0 : mNetworkSpecifier.hashCode() * 17)); 539 } 540 541 @Override 542 public int describeContents() { 543 return 0; 544 } 545 @Override 546 public void writeToParcel(Parcel dest, int flags) { 547 dest.writeLong(mNetworkCapabilities); 548 dest.writeLong(mTransportTypes); 549 dest.writeInt(mLinkUpBandwidthKbps); 550 dest.writeInt(mLinkDownBandwidthKbps); 551 dest.writeString(mNetworkSpecifier); 552 } 553 public static final Creator<NetworkCapabilities> CREATOR = 554 new Creator<NetworkCapabilities>() { 555 @Override 556 public NetworkCapabilities createFromParcel(Parcel in) { 557 NetworkCapabilities netCap = new NetworkCapabilities(); 558 559 netCap.mNetworkCapabilities = in.readLong(); 560 netCap.mTransportTypes = in.readLong(); 561 netCap.mLinkUpBandwidthKbps = in.readInt(); 562 netCap.mLinkDownBandwidthKbps = in.readInt(); 563 netCap.mNetworkSpecifier = in.readString(); 564 return netCap; 565 } 566 @Override 567 public NetworkCapabilities[] newArray(int size) { 568 return new NetworkCapabilities[size]; 569 } 570 }; 571 572 @Override 573 public String toString() { 574 int[] types = getTransportTypes(); 575 String transports = (types.length > 0 ? " Transports: " : ""); 576 for (int i = 0; i < types.length;) { 577 switch (types[i]) { 578 case TRANSPORT_CELLULAR: transports += "CELLULAR"; break; 579 case TRANSPORT_WIFI: transports += "WIFI"; break; 580 case TRANSPORT_BLUETOOTH: transports += "BLUETOOTH"; break; 581 case TRANSPORT_ETHERNET: transports += "ETHERNET"; break; 582 case TRANSPORT_VPN: transports += "VPN"; break; 583 } 584 if (++i < types.length) transports += "|"; 585 } 586 587 types = getCapabilities(); 588 String capabilities = (types.length > 0 ? " Capabilities: " : ""); 589 for (int i = 0; i < types.length; ) { 590 switch (types[i]) { 591 case NET_CAPABILITY_MMS: capabilities += "MMS"; break; 592 case NET_CAPABILITY_SUPL: capabilities += "SUPL"; break; 593 case NET_CAPABILITY_DUN: capabilities += "DUN"; break; 594 case NET_CAPABILITY_FOTA: capabilities += "FOTA"; break; 595 case NET_CAPABILITY_IMS: capabilities += "IMS"; break; 596 case NET_CAPABILITY_CBS: capabilities += "CBS"; break; 597 case NET_CAPABILITY_WIFI_P2P: capabilities += "WIFI_P2P"; break; 598 case NET_CAPABILITY_IA: capabilities += "IA"; break; 599 case NET_CAPABILITY_RCS: capabilities += "RCS"; break; 600 case NET_CAPABILITY_XCAP: capabilities += "XCAP"; break; 601 case NET_CAPABILITY_EIMS: capabilities += "EIMS"; break; 602 case NET_CAPABILITY_NOT_METERED: capabilities += "NOT_METERED"; break; 603 case NET_CAPABILITY_INTERNET: capabilities += "INTERNET"; break; 604 case NET_CAPABILITY_NOT_RESTRICTED: capabilities += "NOT_RESTRICTED"; break; 605 case NET_CAPABILITY_TRUSTED: capabilities += "TRUSTED"; break; 606 case NET_CAPABILITY_NOT_VPN: capabilities += "NOT_VPN"; break; 607 } 608 if (++i < types.length) capabilities += "&"; 609 } 610 611 String upBand = ((mLinkUpBandwidthKbps > 0) ? " LinkUpBandwidth>=" + 612 mLinkUpBandwidthKbps + "Kbps" : ""); 613 String dnBand = ((mLinkDownBandwidthKbps > 0) ? " LinkDnBandwidth>=" + 614 mLinkDownBandwidthKbps + "Kbps" : ""); 615 616 String specifier = (mNetworkSpecifier == null ? 617 "" : " Specifier: <" + mNetworkSpecifier + ">"); 618 619 return "[" + transports + capabilities + upBand + dnBand + specifier + "]"; 620 } 621 } 622