1 /*
2  * Copyright (C) 2008 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.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.compat.annotation.UnsupportedAppUsage;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.text.TextUtils;
25 
26 import com.android.internal.annotations.VisibleForTesting;
27 import com.android.modules.utils.build.SdkLevel;
28 
29 import java.util.EnumMap;
30 
31 /**
32  * Describes the status of a network interface.
33  * <p>Use {@link ConnectivityManager#getActiveNetworkInfo()} to get an instance that represents
34  * the current network connection.
35  *
36  * @deprecated Callers should instead use the {@link ConnectivityManager.NetworkCallback} API to
37  *             learn about connectivity changes, or switch to use
38  *             {@link ConnectivityManager#getNetworkCapabilities} or
39  *             {@link ConnectivityManager#getLinkProperties} to get information synchronously. Keep
40  *             in mind that while callbacks are guaranteed to be called for every event in order,
41  *             synchronous calls have no such constraints, and as such it is unadvisable to use the
42  *             synchronous methods inside the callbacks as they will often not offer a view of
43  *             networking that is consistent (that is: they may return a past or a future state with
44  *             respect to the event being processed by the callback). Instead, callers are advised
45  *             to only use the arguments of the callbacks, possibly memorizing the specific bits of
46  *             information they need to keep from one callback to another.
47  */
48 @Deprecated
49 public class NetworkInfo implements Parcelable {
50 
51     /**
52      * Coarse-grained network state. This is probably what most applications should
53      * use, rather than {@link android.net.NetworkInfo.DetailedState DetailedState}.
54      * The mapping between the two is as follows:
55      * <br/><br/>
56      * <table>
57      * <tr><td><b>Detailed state</b></td><td><b>Coarse-grained state</b></td></tr>
58      * <tr><td><code>IDLE</code></td><td><code>DISCONNECTED</code></td></tr>
59      * <tr><td><code>SCANNING</code></td><td><code>DISCONNECTED</code></td></tr>
60      * <tr><td><code>CONNECTING</code></td><td><code>CONNECTING</code></td></tr>
61      * <tr><td><code>AUTHENTICATING</code></td><td><code>CONNECTING</code></td></tr>
62      * <tr><td><code>OBTAINING_IPADDR</code></td><td><code>CONNECTING</code></td></tr>
63      * <tr><td><code>VERIFYING_POOR_LINK</code></td><td><code>CONNECTING</code></td></tr>
64      * <tr><td><code>CAPTIVE_PORTAL_CHECK</code></td><td><code>CONNECTING</code></td></tr>
65      * <tr><td><code>CONNECTED</code></td><td><code>CONNECTED</code></td></tr>
66      * <tr><td><code>SUSPENDED</code></td><td><code>SUSPENDED</code></td></tr>
67      * <tr><td><code>DISCONNECTING</code></td><td><code>DISCONNECTING</code></td></tr>
68      * <tr><td><code>DISCONNECTED</code></td><td><code>DISCONNECTED</code></td></tr>
69      * <tr><td><code>FAILED</code></td><td><code>DISCONNECTED</code></td></tr>
70      * <tr><td><code>BLOCKED</code></td><td><code>DISCONNECTED</code></td></tr>
71      * </table>
72      *
73      * @deprecated See {@link NetworkInfo}.
74      */
75     @Deprecated
76     public enum State {
77         CONNECTING, CONNECTED, SUSPENDED, DISCONNECTING, DISCONNECTED, UNKNOWN
78     }
79 
80     /**
81      * The fine-grained state of a network connection. This level of detail
82      * is probably of interest to few applications. Most should use
83      * {@link android.net.NetworkInfo.State State} instead.
84      *
85      * @deprecated See {@link NetworkInfo}.
86      */
87     @Deprecated
88     public enum DetailedState {
89         /** Ready to start data connection setup. */
90         IDLE,
91         /** Searching for an available access point. */
92         SCANNING,
93         /** Currently setting up data connection. */
94         CONNECTING,
95         /** Network link established, performing authentication. */
96         AUTHENTICATING,
97         /** Awaiting response from DHCP server in order to assign IP address information. */
98         OBTAINING_IPADDR,
99         /** IP traffic should be available. */
100         CONNECTED,
101         /** IP traffic is suspended */
102         SUSPENDED,
103         /** Currently tearing down data connection. */
104         DISCONNECTING,
105         /** IP traffic not available. */
106         DISCONNECTED,
107         /** Attempt to connect failed. */
108         FAILED,
109         /** Access to this network is blocked. */
110         BLOCKED,
111         /** Link has poor connectivity. */
112         VERIFYING_POOR_LINK,
113         /** Checking if network is a captive portal */
114         CAPTIVE_PORTAL_CHECK
115     }
116 
117     /**
118      * This is the map described in the Javadoc comment above. The positions
119      * of the elements of the array must correspond to the ordinal values
120      * of <code>DetailedState</code>.
121      */
122     private static final EnumMap<DetailedState, State> stateMap =
123         new EnumMap<DetailedState, State>(DetailedState.class);
124 
125     static {
stateMap.put(DetailedState.IDLE, State.DISCONNECTED)126         stateMap.put(DetailedState.IDLE, State.DISCONNECTED);
stateMap.put(DetailedState.SCANNING, State.DISCONNECTED)127         stateMap.put(DetailedState.SCANNING, State.DISCONNECTED);
stateMap.put(DetailedState.CONNECTING, State.CONNECTING)128         stateMap.put(DetailedState.CONNECTING, State.CONNECTING);
stateMap.put(DetailedState.AUTHENTICATING, State.CONNECTING)129         stateMap.put(DetailedState.AUTHENTICATING, State.CONNECTING);
stateMap.put(DetailedState.OBTAINING_IPADDR, State.CONNECTING)130         stateMap.put(DetailedState.OBTAINING_IPADDR, State.CONNECTING);
stateMap.put(DetailedState.VERIFYING_POOR_LINK, State.CONNECTING)131         stateMap.put(DetailedState.VERIFYING_POOR_LINK, State.CONNECTING);
stateMap.put(DetailedState.CAPTIVE_PORTAL_CHECK, State.CONNECTING)132         stateMap.put(DetailedState.CAPTIVE_PORTAL_CHECK, State.CONNECTING);
stateMap.put(DetailedState.CONNECTED, State.CONNECTED)133         stateMap.put(DetailedState.CONNECTED, State.CONNECTED);
stateMap.put(DetailedState.SUSPENDED, State.SUSPENDED)134         stateMap.put(DetailedState.SUSPENDED, State.SUSPENDED);
stateMap.put(DetailedState.DISCONNECTING, State.DISCONNECTING)135         stateMap.put(DetailedState.DISCONNECTING, State.DISCONNECTING);
stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED)136         stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED);
stateMap.put(DetailedState.FAILED, State.DISCONNECTED)137         stateMap.put(DetailedState.FAILED, State.DISCONNECTED);
stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED)138         stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED);
139     }
140 
141     private int mNetworkType;
142     private int mSubtype;
143     private String mTypeName;
144     private String mSubtypeName;
145     @NonNull
146     private State mState;
147     @NonNull
148     private DetailedState mDetailedState;
149     private String mReason;
150     private String mExtraInfo;
151     private boolean mIsFailover;
152     private boolean mIsAvailable;
153     private boolean mIsRoaming;
154 
155     /**
156      * Create a new instance of NetworkInfo.
157      *
158      * This may be useful for apps to write unit tests.
159      *
160      * @param type the legacy type of the network, as one of the ConnectivityManager.TYPE_*
161      *             constants.
162      * @param subtype the subtype if applicable, as one of the TelephonyManager.NETWORK_TYPE_*
163      *                constants.
164      * @param typeName a human-readable string for the network type, or an empty string or null.
165      * @param subtypeName a human-readable string for the subtype, or an empty string or null.
166      */
NetworkInfo(int type, int subtype, @Nullable String typeName, @Nullable String subtypeName)167     public NetworkInfo(int type, int subtype,
168             @Nullable String typeName, @Nullable String subtypeName) {
169         if (!ConnectivityManager.isNetworkTypeValid(type)
170                 && type != ConnectivityManager.TYPE_NONE) {
171             throw new IllegalArgumentException("Invalid network type: " + type);
172         }
173         mNetworkType = type;
174         mSubtype = subtype;
175         mTypeName = typeName;
176         mSubtypeName = subtypeName;
177         setDetailedState(DetailedState.IDLE, null, null);
178         mState = State.UNKNOWN;
179     }
180 
181     /** {@hide} */
182     @UnsupportedAppUsage
NetworkInfo(@onNull NetworkInfo source)183     public NetworkInfo(@NonNull NetworkInfo source) {
184         // S- didn't use to crash when passing null. This plants a timebomb where mState and
185         // some other fields are null, but there may be existing code that relies on this behavior
186         // and doesn't trip the timebomb, so on SdkLevel < T, keep the old behavior. b/145972387
187         if (null == source && !SdkLevel.isAtLeastT()) return;
188         synchronized (source) {
189             mNetworkType = source.mNetworkType;
190             mSubtype = source.mSubtype;
191             mTypeName = source.mTypeName;
192             mSubtypeName = source.mSubtypeName;
193             mState = source.mState;
194             mDetailedState = source.mDetailedState;
195             mReason = source.mReason;
196             mExtraInfo = source.mExtraInfo;
197             mIsFailover = source.mIsFailover;
198             mIsAvailable = source.mIsAvailable;
199             mIsRoaming = source.mIsRoaming;
200         }
201     }
202 
203     /**
204      * Reports the type of network to which the
205      * info in this {@code NetworkInfo} pertains.
206      * @return one of {@link ConnectivityManager#TYPE_MOBILE}, {@link
207      * ConnectivityManager#TYPE_WIFI}, {@link ConnectivityManager#TYPE_WIMAX}, {@link
208      * ConnectivityManager#TYPE_ETHERNET},  {@link ConnectivityManager#TYPE_BLUETOOTH}, or other
209      * types defined by {@link ConnectivityManager}.
210      * @deprecated Callers should switch to checking {@link NetworkCapabilities#hasTransport}
211      *             instead with one of the NetworkCapabilities#TRANSPORT_* constants :
212      *             {@link #getType} and {@link #getTypeName} cannot account for networks using
213      *             multiple transports. Note that generally apps should not care about transport;
214      *             {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED} and
215      *             {@link NetworkCapabilities#getLinkDownstreamBandwidthKbps} are calls that
216      *             apps concerned with meteredness or bandwidth should be looking at, as they
217      *             offer this information with much better accuracy.
218      */
219     @Deprecated
getType()220     public int getType() {
221         synchronized (this) {
222             return mNetworkType;
223         }
224     }
225 
226     /**
227      * @deprecated Use {@link NetworkCapabilities} instead
228      * @hide
229      */
230     @Deprecated
setType(int type)231     public void setType(int type) {
232         synchronized (this) {
233             mNetworkType = type;
234         }
235     }
236 
237     /**
238      * Return a network-type-specific integer describing the subtype
239      * of the network.
240      * @return the network subtype
241      * @deprecated Use {@link android.telephony.TelephonyManager#getDataNetworkType} instead.
242      */
243     @Deprecated
getSubtype()244     public int getSubtype() {
245         synchronized (this) {
246             return mSubtype;
247         }
248     }
249 
250     /**
251      * @hide
252      */
253     @UnsupportedAppUsage
setSubtype(int subtype, String subtypeName)254     public void setSubtype(int subtype, String subtypeName) {
255         synchronized (this) {
256             mSubtype = subtype;
257             mSubtypeName = subtypeName;
258         }
259     }
260 
261     /**
262      * Return a human-readable name describe the type of the network,
263      * for example "WIFI" or "MOBILE".
264      * @return the name of the network type
265      * @deprecated Callers should switch to checking {@link NetworkCapabilities#hasTransport}
266      *             instead with one of the NetworkCapabilities#TRANSPORT_* constants :
267      *             {@link #getType} and {@link #getTypeName} cannot account for networks using
268      *             multiple transports. Note that generally apps should not care about transport;
269      *             {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED} and
270      *             {@link NetworkCapabilities#getLinkDownstreamBandwidthKbps} are calls that
271      *             apps concerned with meteredness or bandwidth should be looking at, as they
272      *             offer this information with much better accuracy.
273      */
274     @Deprecated
getTypeName()275     public String getTypeName() {
276         synchronized (this) {
277             return mTypeName;
278         }
279     }
280 
281     /**
282      * Return a human-readable name describing the subtype of the network.
283      * @return the name of the network subtype
284      * @deprecated Use {@link android.telephony.TelephonyManager#getDataNetworkType} instead.
285      */
286     @Deprecated
getSubtypeName()287     public String getSubtypeName() {
288         synchronized (this) {
289             return mSubtypeName;
290         }
291     }
292 
293     /**
294      * Indicates whether network connectivity exists or is in the process
295      * of being established. This is good for applications that need to
296      * do anything related to the network other than read or write data.
297      * For the latter, call {@link #isConnected()} instead, which guarantees
298      * that the network is fully usable.
299      * @return {@code true} if network connectivity exists or is in the process
300      * of being established, {@code false} otherwise.
301      * @deprecated Apps should instead use the
302      *             {@link android.net.ConnectivityManager.NetworkCallback} API to
303      *             learn about connectivity changes.
304      *             {@link ConnectivityManager#registerDefaultNetworkCallback} and
305      *             {@link ConnectivityManager#registerNetworkCallback}. These will
306      *             give a more accurate picture of the connectivity state of
307      *             the device and let apps react more easily and quickly to changes.
308      */
309     @Deprecated
isConnectedOrConnecting()310     public boolean isConnectedOrConnecting() {
311         synchronized (this) {
312             return mState == State.CONNECTED || mState == State.CONNECTING;
313         }
314     }
315 
316     /**
317      * Indicates whether network connectivity exists and it is possible to establish
318      * connections and pass data.
319      * <p>Always call this before attempting to perform data transactions.
320      * @return {@code true} if network connectivity exists, {@code false} otherwise.
321      * @deprecated Apps should instead use the
322      *             {@link android.net.ConnectivityManager.NetworkCallback} API to
323      *             learn about connectivity changes. See
324      *             {@link ConnectivityManager#registerDefaultNetworkCallback} and
325      *             {@link ConnectivityManager#registerNetworkCallback}. These will
326      *             give a more accurate picture of the connectivity state of
327      *             the device and let apps react more easily and quickly to changes.
328      */
329     @Deprecated
isConnected()330     public boolean isConnected() {
331         synchronized (this) {
332             return mState == State.CONNECTED;
333         }
334     }
335 
336     /**
337      * Indicates whether this network is suspended.
338      * @deprecated Apps should instead use the
339      *             {@link android.net.ConnectivityManager.NetworkCallback} API to
340      *             learn about connectivity changes. See
341      *             {@link ConnectivityManager#registerDefaultNetworkCallback} and
342      *             {@link ConnectivityManager#registerNetworkCallback}. These will
343      *             give a more accurate picture of the connectivity state of
344      *             the device and let apps react more easily and quickly to changes.
345      * @hide
346      */
347     @Deprecated
isSuspended()348     public boolean isSuspended() {
349         synchronized (this) {
350             return mState == State.SUSPENDED;
351         }
352     }
353 
354     /**
355      * Indicates whether network connectivity is possible. A network is unavailable
356      * when a persistent or semi-persistent condition prevents the possibility
357      * of connecting to that network. Examples include
358      * <ul>
359      * <li>The device is out of the coverage area for any network of this type.</li>
360      * <li>The device is on a network other than the home network (i.e., roaming), and
361      * data roaming has been disabled.</li>
362      * <li>The device's radio is turned off, e.g., because airplane mode is enabled.</li>
363      * </ul>
364      * Since Android L, this always returns {@code true}, because the system only
365      * returns info for available networks.
366      * @return {@code true} if the network is available, {@code false} otherwise
367      * @deprecated Apps should instead use the
368      *             {@link android.net.ConnectivityManager.NetworkCallback} API to
369      *             learn about connectivity changes.
370      *             {@link ConnectivityManager#registerDefaultNetworkCallback} and
371      *             {@link ConnectivityManager#registerNetworkCallback}. These will
372      *             give a more accurate picture of the connectivity state of
373      *             the device and let apps react more easily and quickly to changes.
374      */
375     @Deprecated
isAvailable()376     public boolean isAvailable() {
377         synchronized (this) {
378             return mIsAvailable;
379         }
380     }
381 
382     /**
383      * Sets if the network is available, ie, if the connectivity is possible.
384      * @param isAvailable the new availability value.
385      * @deprecated Use {@link NetworkCapabilities} instead
386      *
387      * @hide
388      */
389     @Deprecated
390     @UnsupportedAppUsage
setIsAvailable(boolean isAvailable)391     public void setIsAvailable(boolean isAvailable) {
392         synchronized (this) {
393             mIsAvailable = isAvailable;
394         }
395     }
396 
397     /**
398      * Indicates whether the current attempt to connect to the network
399      * resulted from the ConnectivityManager trying to fail over to this
400      * network following a disconnect from another network.
401      * @return {@code true} if this is a failover attempt, {@code false}
402      * otherwise.
403      * @deprecated This field is not populated in recent Android releases,
404      *             and does not make a lot of sense in a multi-network world.
405      */
406     @Deprecated
isFailover()407     public boolean isFailover() {
408         synchronized (this) {
409             return mIsFailover;
410         }
411     }
412 
413     /**
414      * Set the failover boolean.
415      * @param isFailover {@code true} to mark the current connection attempt
416      * as a failover.
417      * @deprecated This hasn't been set in any recent Android release.
418      * @hide
419      */
420     @Deprecated
421     @UnsupportedAppUsage
setFailover(boolean isFailover)422     public void setFailover(boolean isFailover) {
423         synchronized (this) {
424             mIsFailover = isFailover;
425         }
426     }
427 
428     /**
429      * Indicates whether the device is currently roaming on this network. When
430      * {@code true}, it suggests that use of data on this network may incur
431      * extra costs.
432      *
433      * @return {@code true} if roaming is in effect, {@code false} otherwise.
434      * @deprecated Callers should switch to checking
435      *             {@link NetworkCapabilities#NET_CAPABILITY_NOT_ROAMING}
436      *             instead, since that handles more complex situations, such as
437      *             VPNs.
438      */
439     @Deprecated
isRoaming()440     public boolean isRoaming() {
441         synchronized (this) {
442             return mIsRoaming;
443         }
444     }
445 
446     /**
447      * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_NOT_ROAMING} instead.
448      * {@hide}
449      */
450     @VisibleForTesting
451     @Deprecated
452     @UnsupportedAppUsage
setRoaming(boolean isRoaming)453     public void setRoaming(boolean isRoaming) {
454         synchronized (this) {
455             mIsRoaming = isRoaming;
456         }
457     }
458 
459     /**
460      * Reports the current coarse-grained state of the network.
461      * @return the coarse-grained state
462      * @deprecated Apps should instead use the
463      *             {@link android.net.ConnectivityManager.NetworkCallback} API to
464      *             learn about connectivity changes.
465      *             {@link ConnectivityManager#registerDefaultNetworkCallback} and
466      *             {@link ConnectivityManager#registerNetworkCallback}. These will
467      *             give a more accurate picture of the connectivity state of
468      *             the device and let apps react more easily and quickly to changes.
469      */
470     @Deprecated
getState()471     public State getState() {
472         synchronized (this) {
473             return mState;
474         }
475     }
476 
477     /**
478      * Reports the current fine-grained state of the network.
479      * @return the fine-grained state
480      * @deprecated Apps should instead use the
481      *             {@link android.net.ConnectivityManager.NetworkCallback} API to
482      *             learn about connectivity changes. See
483      *             {@link ConnectivityManager#registerDefaultNetworkCallback} and
484      *             {@link ConnectivityManager#registerNetworkCallback}. These will
485      *             give a more accurate picture of the connectivity state of
486      *             the device and let apps react more easily and quickly to changes.
487      */
488     @Deprecated
getDetailedState()489     public @NonNull DetailedState getDetailedState() {
490         synchronized (this) {
491             return mDetailedState;
492         }
493     }
494 
495     /**
496      * Sets the fine-grained state of the network.
497      *
498      * This is only useful for testing.
499      *
500      * @param detailedState the {@link DetailedState}.
501      * @param reason a {@code String} indicating the reason for the state change,
502      * if one was supplied. May be {@code null}.
503      * @param extraInfo an optional {@code String} providing additional network state
504      * information passed up from the lower networking layers.
505      * @deprecated Use {@link NetworkCapabilities} instead.
506      */
507     @Deprecated
setDetailedState(@onNull DetailedState detailedState, @Nullable String reason, @Nullable String extraInfo)508     public void setDetailedState(@NonNull DetailedState detailedState, @Nullable String reason,
509             @Nullable String extraInfo) {
510         synchronized (this) {
511             this.mDetailedState = detailedState;
512             this.mState = stateMap.get(detailedState);
513             this.mReason = reason;
514             this.mExtraInfo = extraInfo;
515             // Catch both the case where detailedState is null and the case where it's some
516             // unknown value. This is clearly incorrect usage, but S- didn't use to crash (at
517             // least immediately) so keep the old behavior on older frameworks for safety.
518             if (null == mState && SdkLevel.isAtLeastT()) {
519                 throw new NullPointerException("Unknown DetailedState : " + detailedState);
520             }
521         }
522     }
523 
524     /**
525      * Set the extraInfo field.
526      * @param extraInfo an optional {@code String} providing addditional network state
527      * information passed up from the lower networking layers.
528      * @deprecated See {@link NetworkInfo#getExtraInfo}.
529      * @hide
530      */
531     @Deprecated
setExtraInfo(String extraInfo)532     public void setExtraInfo(String extraInfo) {
533         synchronized (this) {
534             this.mExtraInfo = extraInfo;
535         }
536     }
537 
538     /**
539      * Report the reason an attempt to establish connectivity failed,
540      * if one is available.
541      * @return the reason for failure, or null if not available
542      * @deprecated This method does not have a consistent contract that could make it useful
543      *             to callers.
544      */
getReason()545     public String getReason() {
546         synchronized (this) {
547             return mReason;
548         }
549     }
550 
551     /**
552      * Report the extra information about the network state, if any was
553      * provided by the lower networking layers.
554      * @return the extra information, or null if not available
555      * @deprecated Use other services e.g. WifiManager to get additional information passed up from
556      *             the lower networking layers.
557      */
558     @Deprecated
getExtraInfo()559     public String getExtraInfo() {
560         synchronized (this) {
561             return mExtraInfo;
562         }
563     }
564 
565     @Override
toString()566     public String toString() {
567         synchronized (this) {
568             final StringBuilder builder = new StringBuilder("[");
569             builder.append("type: ").append(getTypeName()).append("[").append(getSubtypeName()).
570             append("], state: ").append(mState).append("/").append(mDetailedState).
571             append(", reason: ").append(mReason == null ? "(unspecified)" : mReason).
572             append(", extra: ").append(mExtraInfo == null ? "(none)" : mExtraInfo).
573             append(", failover: ").append(mIsFailover).
574             append(", available: ").append(mIsAvailable).
575             append(", roaming: ").append(mIsRoaming).
576             append("]");
577             return builder.toString();
578         }
579     }
580 
581     /**
582      * Returns a brief summary string suitable for debugging.
583      * @hide
584      */
toShortString()585     public String toShortString() {
586         synchronized (this) {
587             final StringBuilder builder = new StringBuilder();
588             builder.append(getTypeName());
589 
590             final String subtype = getSubtypeName();
591             if (!TextUtils.isEmpty(subtype)) {
592                 builder.append("[").append(subtype).append("]");
593             }
594 
595             builder.append(" ");
596             builder.append(mDetailedState);
597             if (mIsRoaming) {
598                 builder.append(" ROAMING");
599             }
600             if (mExtraInfo != null) {
601                 builder.append(" extra: ").append(mExtraInfo);
602             }
603             return builder.toString();
604         }
605     }
606 
607     @Override
describeContents()608     public int describeContents() {
609         return 0;
610     }
611 
612     @Override
writeToParcel(Parcel dest, int flags)613     public void writeToParcel(Parcel dest, int flags) {
614         synchronized (this) {
615             dest.writeInt(mNetworkType);
616             dest.writeInt(mSubtype);
617             dest.writeString(mTypeName);
618             dest.writeString(mSubtypeName);
619             dest.writeString(mState.name());
620             dest.writeString(mDetailedState.name());
621             dest.writeInt(mIsFailover ? 1 : 0);
622             dest.writeInt(mIsAvailable ? 1 : 0);
623             dest.writeInt(mIsRoaming ? 1 : 0);
624             dest.writeString(mReason);
625             dest.writeString(mExtraInfo);
626         }
627     }
628 
629     public static final @android.annotation.NonNull Creator<NetworkInfo> CREATOR = new Creator<NetworkInfo>() {
630         @Override
631         public NetworkInfo createFromParcel(Parcel in) {
632             int netType = in.readInt();
633             int subtype = in.readInt();
634             String typeName = in.readString();
635             String subtypeName = in.readString();
636             NetworkInfo netInfo = new NetworkInfo(netType, subtype, typeName, subtypeName);
637             netInfo.mState = State.valueOf(in.readString());
638             netInfo.mDetailedState = DetailedState.valueOf(in.readString());
639             netInfo.mIsFailover = in.readInt() != 0;
640             netInfo.mIsAvailable = in.readInt() != 0;
641             netInfo.mIsRoaming = in.readInt() != 0;
642             netInfo.mReason = in.readString();
643             netInfo.mExtraInfo = in.readString();
644             return netInfo;
645         }
646 
647         @Override
648         public NetworkInfo[] newArray(int size) {
649             return new NetworkInfo[size];
650         }
651     };
652 }
653