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