Home | History | Annotate | Download | only in net
      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