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.os.Parcelable;
20 import android.os.Parcel;
21 
22 import com.android.internal.annotations.VisibleForTesting;
23 
24 import java.util.EnumMap;
25 
26 /**
27  * Describes the status of a network interface.
28  * <p>Use {@link ConnectivityManager#getActiveNetworkInfo()} to get an instance that represents
29  * the current network connection.
30  */
31 public class NetworkInfo implements Parcelable {
32 
33     /**
34      * Coarse-grained network state. This is probably what most applications should
35      * use, rather than {@link android.net.NetworkInfo.DetailedState DetailedState}.
36      * The mapping between the two is as follows:
37      * <br/><br/>
38      * <table>
39      * <tr><td><b>Detailed state</b></td><td><b>Coarse-grained state</b></td></tr>
40      * <tr><td><code>IDLE</code></td><td><code>DISCONNECTED</code></td></tr>
41      * <tr><td><code>SCANNING</code></td><td><code>CONNECTING</code></td></tr>
42      * <tr><td><code>CONNECTING</code></td><td><code>CONNECTING</code></td></tr>
43      * <tr><td><code>AUTHENTICATING</code></td><td><code>CONNECTING</code></td></tr>
44      * <tr><td><code>CONNECTED</code></td><td><code>CONNECTED</code></td></tr>
45      * <tr><td><code>DISCONNECTING</code></td><td><code>DISCONNECTING</code></td></tr>
46      * <tr><td><code>DISCONNECTED</code></td><td><code>DISCONNECTED</code></td></tr>
47      * <tr><td><code>UNAVAILABLE</code></td><td><code>DISCONNECTED</code></td></tr>
48      * <tr><td><code>FAILED</code></td><td><code>DISCONNECTED</code></td></tr>
49      * </table>
50      */
51     public enum State {
52         CONNECTING, CONNECTED, SUSPENDED, DISCONNECTING, DISCONNECTED, UNKNOWN
53     }
54 
55     /**
56      * The fine-grained state of a network connection. This level of detail
57      * is probably of interest to few applications. Most should use
58      * {@link android.net.NetworkInfo.State State} instead.
59      */
60     public enum DetailedState {
61         /** Ready to start data connection setup. */
62         IDLE,
63         /** Searching for an available access point. */
64         SCANNING,
65         /** Currently setting up data connection. */
66         CONNECTING,
67         /** Network link established, performing authentication. */
68         AUTHENTICATING,
69         /** Awaiting response from DHCP server in order to assign IP address information. */
70         OBTAINING_IPADDR,
71         /** IP traffic should be available. */
72         CONNECTED,
73         /** IP traffic is suspended */
74         SUSPENDED,
75         /** Currently tearing down data connection. */
76         DISCONNECTING,
77         /** IP traffic not available. */
78         DISCONNECTED,
79         /** Attempt to connect failed. */
80         FAILED,
81         /** Access to this network is blocked. */
82         BLOCKED,
83         /** Link has poor connectivity. */
84         VERIFYING_POOR_LINK,
85         /** Checking if network is a captive portal */
86         CAPTIVE_PORTAL_CHECK
87     }
88 
89     /**
90      * This is the map described in the Javadoc comment above. The positions
91      * of the elements of the array must correspond to the ordinal values
92      * of <code>DetailedState</code>.
93      */
94     private static final EnumMap<DetailedState, State> stateMap =
95         new EnumMap<DetailedState, State>(DetailedState.class);
96 
97     static {
stateMap.put(DetailedState.IDLE, State.DISCONNECTED)98         stateMap.put(DetailedState.IDLE, State.DISCONNECTED);
stateMap.put(DetailedState.SCANNING, State.DISCONNECTED)99         stateMap.put(DetailedState.SCANNING, State.DISCONNECTED);
stateMap.put(DetailedState.CONNECTING, State.CONNECTING)100         stateMap.put(DetailedState.CONNECTING, State.CONNECTING);
stateMap.put(DetailedState.AUTHENTICATING, State.CONNECTING)101         stateMap.put(DetailedState.AUTHENTICATING, State.CONNECTING);
stateMap.put(DetailedState.OBTAINING_IPADDR, State.CONNECTING)102         stateMap.put(DetailedState.OBTAINING_IPADDR, State.CONNECTING);
stateMap.put(DetailedState.VERIFYING_POOR_LINK, State.CONNECTING)103         stateMap.put(DetailedState.VERIFYING_POOR_LINK, State.CONNECTING);
stateMap.put(DetailedState.CAPTIVE_PORTAL_CHECK, State.CONNECTING)104         stateMap.put(DetailedState.CAPTIVE_PORTAL_CHECK, State.CONNECTING);
stateMap.put(DetailedState.CONNECTED, State.CONNECTED)105         stateMap.put(DetailedState.CONNECTED, State.CONNECTED);
stateMap.put(DetailedState.SUSPENDED, State.SUSPENDED)106         stateMap.put(DetailedState.SUSPENDED, State.SUSPENDED);
stateMap.put(DetailedState.DISCONNECTING, State.DISCONNECTING)107         stateMap.put(DetailedState.DISCONNECTING, State.DISCONNECTING);
stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED)108         stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED);
stateMap.put(DetailedState.FAILED, State.DISCONNECTED)109         stateMap.put(DetailedState.FAILED, State.DISCONNECTED);
stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED)110         stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED);
111     }
112 
113     private int mNetworkType;
114     private int mSubtype;
115     private String mTypeName;
116     private String mSubtypeName;
117     private State mState;
118     private DetailedState mDetailedState;
119     private String mReason;
120     private String mExtraInfo;
121     private boolean mIsFailover;
122     private boolean mIsAvailable;
123     private boolean mIsRoaming;
124     private boolean mIsMetered;
125 
126     /**
127      * @hide
128      */
NetworkInfo(int type, int subtype, String typeName, String subtypeName)129     public NetworkInfo(int type, int subtype, String typeName, String subtypeName) {
130         if (!ConnectivityManager.isNetworkTypeValid(type)) {
131             throw new IllegalArgumentException("Invalid network type: " + type);
132         }
133         mNetworkType = type;
134         mSubtype = subtype;
135         mTypeName = typeName;
136         mSubtypeName = subtypeName;
137         setDetailedState(DetailedState.IDLE, null, null);
138         mState = State.UNKNOWN;
139     }
140 
141     /** {@hide} */
NetworkInfo(NetworkInfo source)142     public NetworkInfo(NetworkInfo source) {
143         if (source != null) {
144             synchronized (source) {
145                 mNetworkType = source.mNetworkType;
146                 mSubtype = source.mSubtype;
147                 mTypeName = source.mTypeName;
148                 mSubtypeName = source.mSubtypeName;
149                 mState = source.mState;
150                 mDetailedState = source.mDetailedState;
151                 mReason = source.mReason;
152                 mExtraInfo = source.mExtraInfo;
153                 mIsFailover = source.mIsFailover;
154                 mIsAvailable = source.mIsAvailable;
155                 mIsRoaming = source.mIsRoaming;
156                 mIsMetered = source.mIsMetered;
157             }
158         }
159     }
160 
161     /**
162      * Reports the type of network to which the
163      * info in this {@code NetworkInfo} pertains.
164      * @return one of {@link ConnectivityManager#TYPE_MOBILE}, {@link
165      * ConnectivityManager#TYPE_WIFI}, {@link ConnectivityManager#TYPE_WIMAX}, {@link
166      * ConnectivityManager#TYPE_ETHERNET},  {@link ConnectivityManager#TYPE_BLUETOOTH}, or other
167      * types defined by {@link ConnectivityManager}
168      */
getType()169     public int getType() {
170         synchronized (this) {
171             return mNetworkType;
172         }
173     }
174 
175     /**
176      * @hide
177      */
setType(int type)178     public void setType(int type) {
179         synchronized (this) {
180             mNetworkType = type;
181         }
182     }
183 
184     /**
185      * Return a network-type-specific integer describing the subtype
186      * of the network.
187      * @return the network subtype
188      */
getSubtype()189     public int getSubtype() {
190         synchronized (this) {
191             return mSubtype;
192         }
193     }
194 
195     /**
196      * @hide
197      */
setSubtype(int subtype, String subtypeName)198     public void setSubtype(int subtype, String subtypeName) {
199         synchronized (this) {
200             mSubtype = subtype;
201             mSubtypeName = subtypeName;
202         }
203     }
204 
205     /**
206      * Return a human-readable name describe the type of the network,
207      * for example "WIFI" or "MOBILE".
208      * @return the name of the network type
209      */
getTypeName()210     public String getTypeName() {
211         synchronized (this) {
212             return mTypeName;
213         }
214     }
215 
216     /**
217      * Return a human-readable name describing the subtype of the network.
218      * @return the name of the network subtype
219      */
getSubtypeName()220     public String getSubtypeName() {
221         synchronized (this) {
222             return mSubtypeName;
223         }
224     }
225 
226     /**
227      * Indicates whether network connectivity exists or is in the process
228      * of being established. This is good for applications that need to
229      * do anything related to the network other than read or write data.
230      * For the latter, call {@link #isConnected()} instead, which guarantees
231      * that the network is fully usable.
232      * @return {@code true} if network connectivity exists or is in the process
233      * of being established, {@code false} otherwise.
234      */
isConnectedOrConnecting()235     public boolean isConnectedOrConnecting() {
236         synchronized (this) {
237             return mState == State.CONNECTED || mState == State.CONNECTING;
238         }
239     }
240 
241     /**
242      * Indicates whether network connectivity exists and it is possible to establish
243      * connections and pass data.
244      * <p>Always call this before attempting to perform data transactions.
245      * @return {@code true} if network connectivity exists, {@code false} otherwise.
246      */
isConnected()247     public boolean isConnected() {
248         synchronized (this) {
249             return mState == State.CONNECTED;
250         }
251     }
252 
253     /**
254      * Indicates whether network connectivity is possible. A network is unavailable
255      * when a persistent or semi-persistent condition prevents the possibility
256      * of connecting to that network. Examples include
257      * <ul>
258      * <li>The device is out of the coverage area for any network of this type.</li>
259      * <li>The device is on a network other than the home network (i.e., roaming), and
260      * data roaming has been disabled.</li>
261      * <li>The device's radio is turned off, e.g., because airplane mode is enabled.</li>
262      * </ul>
263      * @return {@code true} if the network is available, {@code false} otherwise
264      */
isAvailable()265     public boolean isAvailable() {
266         synchronized (this) {
267             return mIsAvailable;
268         }
269     }
270 
271     /**
272      * Sets if the network is available, ie, if the connectivity is possible.
273      * @param isAvailable the new availability value.
274      *
275      * @hide
276      */
setIsAvailable(boolean isAvailable)277     public void setIsAvailable(boolean isAvailable) {
278         synchronized (this) {
279             mIsAvailable = isAvailable;
280         }
281     }
282 
283     /**
284      * Indicates whether the current attempt to connect to the network
285      * resulted from the ConnectivityManager trying to fail over to this
286      * network following a disconnect from another network.
287      * @return {@code true} if this is a failover attempt, {@code false}
288      * otherwise.
289      */
isFailover()290     public boolean isFailover() {
291         synchronized (this) {
292             return mIsFailover;
293         }
294     }
295 
296     /**
297      * Set the failover boolean.
298      * @param isFailover {@code true} to mark the current connection attempt
299      * as a failover.
300      * @hide
301      */
setFailover(boolean isFailover)302     public void setFailover(boolean isFailover) {
303         synchronized (this) {
304             mIsFailover = isFailover;
305         }
306     }
307 
308     /**
309      * Indicates whether the device is currently roaming on this network.
310      * When {@code true}, it suggests that use of data on this network
311      * may incur extra costs.
312      * @return {@code true} if roaming is in effect, {@code false} otherwise.
313      */
isRoaming()314     public boolean isRoaming() {
315         synchronized (this) {
316             return mIsRoaming;
317         }
318     }
319 
320     /** {@hide} */
321     @VisibleForTesting
setRoaming(boolean isRoaming)322     public void setRoaming(boolean isRoaming) {
323         synchronized (this) {
324             mIsRoaming = isRoaming;
325         }
326     }
327 
328     /**
329      * Returns if this network is metered. A network is classified as metered
330      * when the user is sensitive to heavy data usage on that connection due to
331      * monetary costs, data limitations or battery/performance issues. You
332      * should check this before doing large data transfers, and warn the user or
333      * delay the operation until another network is available.
334      *
335      * @return {@code true} if large transfers should be avoided, otherwise
336      *         {@code false}.
337      * @hide
338      */
isMetered()339     public boolean isMetered() {
340         synchronized (this) {
341             return mIsMetered;
342         }
343     }
344 
345     /** {@hide} */
346     @VisibleForTesting
setMetered(boolean isMetered)347     public void setMetered(boolean isMetered) {
348         synchronized (this) {
349             mIsMetered = isMetered;
350         }
351     }
352 
353     /**
354      * Reports the current coarse-grained state of the network.
355      * @return the coarse-grained state
356      */
getState()357     public State getState() {
358         synchronized (this) {
359             return mState;
360         }
361     }
362 
363     /**
364      * Reports the current fine-grained state of the network.
365      * @return the fine-grained state
366      */
getDetailedState()367     public DetailedState getDetailedState() {
368         synchronized (this) {
369             return mDetailedState;
370         }
371     }
372 
373     /**
374      * Sets the fine-grained state of the network.
375      * @param detailedState the {@link DetailedState}.
376      * @param reason a {@code String} indicating the reason for the state change,
377      * if one was supplied. May be {@code null}.
378      * @param extraInfo an optional {@code String} providing addditional network state
379      * information passed up from the lower networking layers.
380      * @hide
381      */
setDetailedState(DetailedState detailedState, String reason, String extraInfo)382     public void setDetailedState(DetailedState detailedState, String reason, String extraInfo) {
383         synchronized (this) {
384             this.mDetailedState = detailedState;
385             this.mState = stateMap.get(detailedState);
386             this.mReason = reason;
387             this.mExtraInfo = extraInfo;
388         }
389     }
390 
391     /**
392      * Set the extraInfo field.
393      * @param extraInfo an optional {@code String} providing addditional network state
394      * information passed up from the lower networking layers.
395      * @hide
396      */
setExtraInfo(String extraInfo)397     public void setExtraInfo(String extraInfo) {
398         synchronized (this) {
399             this.mExtraInfo = extraInfo;
400         }
401     }
402 
403     /**
404      * Report the reason an attempt to establish connectivity failed,
405      * if one is available.
406      * @return the reason for failure, or null if not available
407      */
getReason()408     public String getReason() {
409         synchronized (this) {
410             return mReason;
411         }
412     }
413 
414     /**
415      * Report the extra information about the network state, if any was
416      * provided by the lower networking layers.
417      * @return the extra information, or null if not available
418      */
getExtraInfo()419     public String getExtraInfo() {
420         synchronized (this) {
421             return mExtraInfo;
422         }
423     }
424 
425     @Override
toString()426     public String toString() {
427         synchronized (this) {
428             StringBuilder builder = new StringBuilder("[");
429             builder.append("type: ").append(getTypeName()).append("[").append(getSubtypeName()).
430             append("], state: ").append(mState).append("/").append(mDetailedState).
431             append(", reason: ").append(mReason == null ? "(unspecified)" : mReason).
432             append(", extra: ").append(mExtraInfo == null ? "(none)" : mExtraInfo).
433             append(", failover: ").append(mIsFailover).
434             append(", available: ").append(mIsAvailable).
435             append(", roaming: ").append(mIsRoaming).
436             append(", metered: ").append(mIsMetered).
437             append("]");
438             return builder.toString();
439         }
440     }
441 
442     @Override
describeContents()443     public int describeContents() {
444         return 0;
445     }
446 
447     @Override
writeToParcel(Parcel dest, int flags)448     public void writeToParcel(Parcel dest, int flags) {
449         synchronized (this) {
450             dest.writeInt(mNetworkType);
451             dest.writeInt(mSubtype);
452             dest.writeString(mTypeName);
453             dest.writeString(mSubtypeName);
454             dest.writeString(mState.name());
455             dest.writeString(mDetailedState.name());
456             dest.writeInt(mIsFailover ? 1 : 0);
457             dest.writeInt(mIsAvailable ? 1 : 0);
458             dest.writeInt(mIsRoaming ? 1 : 0);
459             dest.writeInt(mIsMetered ? 1 : 0);
460             dest.writeString(mReason);
461             dest.writeString(mExtraInfo);
462         }
463     }
464 
465     public static final Creator<NetworkInfo> CREATOR = new Creator<NetworkInfo>() {
466         @Override
467         public NetworkInfo createFromParcel(Parcel in) {
468             int netType = in.readInt();
469             int subtype = in.readInt();
470             String typeName = in.readString();
471             String subtypeName = in.readString();
472             NetworkInfo netInfo = new NetworkInfo(netType, subtype, typeName, subtypeName);
473             netInfo.mState = State.valueOf(in.readString());
474             netInfo.mDetailedState = DetailedState.valueOf(in.readString());
475             netInfo.mIsFailover = in.readInt() != 0;
476             netInfo.mIsAvailable = in.readInt() != 0;
477             netInfo.mIsRoaming = in.readInt() != 0;
478             netInfo.mIsMetered = in.readInt() != 0;
479             netInfo.mReason = in.readString();
480             netInfo.mExtraInfo = in.readString();
481             return netInfo;
482         }
483 
484         @Override
485         public NetworkInfo[] newArray(int size) {
486             return new NetworkInfo[size];
487         }
488     };
489 }
490