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      */
NetworkCapabilities()39     public NetworkCapabilities() {
40     }
41 
NetworkCapabilities(NetworkCapabilities nc)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      */
addCapability(int capability)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      */
removeCapability(int capability)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      */
getCapabilities()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      */
hasCapability(int capability)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 
enumerateBits(long val)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 
combineNetCapabilities(NetworkCapabilities nc)237     private void combineNetCapabilities(NetworkCapabilities nc) {
238         this.mNetworkCapabilities |= nc.mNetworkCapabilities;
239     }
240 
satisfiedByNetCapabilities(NetworkCapabilities nc)241     private boolean satisfiedByNetCapabilities(NetworkCapabilities nc) {
242         return ((nc.mNetworkCapabilities & this.mNetworkCapabilities) == this.mNetworkCapabilities);
243     }
244 
245     /** @hide */
equalsNetCapabilities(NetworkCapabilities nc)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      */
addTransportType(int transportType)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      */
removeTransportType(int transportType)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      */
getTransportTypes()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      */
hasTransport(int transportType)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 
combineTransportTypes(NetworkCapabilities nc)348     private void combineTransportTypes(NetworkCapabilities nc) {
349         this.mTransportTypes |= nc.mTransportTypes;
350     }
satisfiedByTransportTypes(NetworkCapabilities nc)351     private boolean satisfiedByTransportTypes(NetworkCapabilities nc) {
352         return ((this.mTransportTypes == 0) ||
353                 ((this.mTransportTypes & nc.mTransportTypes) != 0));
354     }
355     /** @hide */
equalsTransportTypes(NetworkCapabilities nc)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      */
setLinkUpstreamBandwidthKbps(int upKbps)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      */
getLinkUpstreamBandwidthKbps()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      */
setLinkDownstreamBandwidthKbps(int downKbps)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      */
getLinkDownstreamBandwidthKbps()422     public int getLinkDownstreamBandwidthKbps() {
423         return mLinkDownBandwidthKbps;
424     }
425 
combineLinkBandwidths(NetworkCapabilities nc)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     }
satisfiedByLinkBandwidths(NetworkCapabilities nc)432     private boolean satisfiedByLinkBandwidths(NetworkCapabilities nc) {
433         return !(this.mLinkUpBandwidthKbps > nc.mLinkUpBandwidthKbps ||
434                 this.mLinkDownBandwidthKbps > nc.mLinkDownBandwidthKbps);
435     }
equalsLinkBandwidths(NetworkCapabilities nc)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      */
setNetworkSpecifier(String networkSpecifier)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      */
getNetworkSpecifier()473     public String getNetworkSpecifier() {
474         return mNetworkSpecifier;
475     }
476 
combineSpecifiers(NetworkCapabilities nc)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     }
satisfiedBySpecifier(NetworkCapabilities nc)485     private boolean satisfiedBySpecifier(NetworkCapabilities nc) {
486         return (TextUtils.isEmpty(mNetworkSpecifier) ||
487                 mNetworkSpecifier.equals(nc.mNetworkSpecifier));
488     }
equalsSpecifier(NetworkCapabilities nc)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      */
combineCapabilities(NetworkCapabilities nc)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      */
satisfiedByNetworkCapabilities(NetworkCapabilities nc)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
equals(Object obj)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
hashCode()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
describeContents()542     public int describeContents() {
543         return 0;
544     }
545     @Override
writeToParcel(Parcel dest, int flags)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
toString()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