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 com.android.internal.annotations.VisibleForTesting;
23
24import 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 */
31public 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 {
98        stateMap.put(DetailedState.IDLE, State.DISCONNECTED);
99        stateMap.put(DetailedState.SCANNING, State.DISCONNECTED);
100        stateMap.put(DetailedState.CONNECTING, State.CONNECTING);
101        stateMap.put(DetailedState.AUTHENTICATING, State.CONNECTING);
102        stateMap.put(DetailedState.OBTAINING_IPADDR, State.CONNECTING);
103        stateMap.put(DetailedState.VERIFYING_POOR_LINK, State.CONNECTING);
104        stateMap.put(DetailedState.CAPTIVE_PORTAL_CHECK, State.CONNECTING);
105        stateMap.put(DetailedState.CONNECTED, State.CONNECTED);
106        stateMap.put(DetailedState.SUSPENDED, State.SUSPENDED);
107        stateMap.put(DetailedState.DISCONNECTING, State.DISCONNECTING);
108        stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED);
109        stateMap.put(DetailedState.FAILED, 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 mIsRoaming;
123    /**
124     * Indicates whether network connectivity is possible:
125     */
126    private boolean mIsAvailable;
127
128    /**
129     * @param type network type
130     * @deprecated
131     * @hide because this constructor was only meant for internal use (and
132     * has now been superseded by the package-private constructor below).
133     */
134    public NetworkInfo(int type) {}
135
136    /**
137     * @hide
138     */
139    public NetworkInfo(int type, int subtype, String typeName, String subtypeName) {
140        if (!ConnectivityManager.isNetworkTypeValid(type)) {
141            throw new IllegalArgumentException("Invalid network type: " + type);
142        }
143        mNetworkType = type;
144        mSubtype = subtype;
145        mTypeName = typeName;
146        mSubtypeName = subtypeName;
147        setDetailedState(DetailedState.IDLE, null, null);
148        mState = State.UNKNOWN;
149        mIsAvailable = false; // until we're told otherwise, assume unavailable
150        mIsRoaming = false;
151    }
152
153    /** {@hide} */
154    public NetworkInfo(NetworkInfo source) {
155        if (source != null) {
156            mNetworkType = source.mNetworkType;
157            mSubtype = source.mSubtype;
158            mTypeName = source.mTypeName;
159            mSubtypeName = source.mSubtypeName;
160            mState = source.mState;
161            mDetailedState = source.mDetailedState;
162            mReason = source.mReason;
163            mExtraInfo = source.mExtraInfo;
164            mIsFailover = source.mIsFailover;
165            mIsRoaming = source.mIsRoaming;
166            mIsAvailable = source.mIsAvailable;
167        }
168    }
169
170    /**
171     * Reports the type of network to which the
172     * info in this {@code NetworkInfo} pertains.
173     * @return one of {@link ConnectivityManager#TYPE_MOBILE}, {@link
174     * ConnectivityManager#TYPE_WIFI}, {@link ConnectivityManager#TYPE_WIMAX}, {@link
175     * ConnectivityManager#TYPE_ETHERNET},  {@link ConnectivityManager#TYPE_BLUETOOTH}, or other
176     * types defined by {@link ConnectivityManager}
177     */
178    public int getType() {
179        synchronized (this) {
180            return mNetworkType;
181        }
182    }
183
184    /**
185     * Return a network-type-specific integer describing the subtype
186     * of the network.
187     * @return the network subtype
188     */
189    public int getSubtype() {
190        synchronized (this) {
191            return mSubtype;
192        }
193    }
194
195    void setSubtype(int subtype, String subtypeName) {
196        synchronized (this) {
197            mSubtype = subtype;
198            mSubtypeName = subtypeName;
199        }
200    }
201
202    /**
203     * Return a human-readable name describe the type of the network,
204     * for example "WIFI" or "MOBILE".
205     * @return the name of the network type
206     */
207    public String getTypeName() {
208        synchronized (this) {
209            return mTypeName;
210        }
211    }
212
213    /**
214     * Return a human-readable name describing the subtype of the network.
215     * @return the name of the network subtype
216     */
217    public String getSubtypeName() {
218        synchronized (this) {
219            return mSubtypeName;
220        }
221    }
222
223    /**
224     * Indicates whether network connectivity exists or is in the process
225     * of being established. This is good for applications that need to
226     * do anything related to the network other than read or write data.
227     * For the latter, call {@link #isConnected()} instead, which guarantees
228     * that the network is fully usable.
229     * @return {@code true} if network connectivity exists or is in the process
230     * of being established, {@code false} otherwise.
231     */
232    public boolean isConnectedOrConnecting() {
233        synchronized (this) {
234            return mState == State.CONNECTED || mState == State.CONNECTING;
235        }
236    }
237
238    /**
239     * Indicates whether network connectivity exists and it is possible to establish
240     * connections and pass data.
241     * <p>Always call this before attempting to perform data transactions.
242     * @return {@code true} if network connectivity exists, {@code false} otherwise.
243     */
244    public boolean isConnected() {
245        synchronized (this) {
246            return mState == State.CONNECTED;
247        }
248    }
249
250    /**
251     * Indicates whether network connectivity is possible. A network is unavailable
252     * when a persistent or semi-persistent condition prevents the possibility
253     * of connecting to that network. Examples include
254     * <ul>
255     * <li>The device is out of the coverage area for any network of this type.</li>
256     * <li>The device is on a network other than the home network (i.e., roaming), and
257     * data roaming has been disabled.</li>
258     * <li>The device's radio is turned off, e.g., because airplane mode is enabled.</li>
259     * </ul>
260     * @return {@code true} if the network is available, {@code false} otherwise
261     */
262    public boolean isAvailable() {
263        synchronized (this) {
264            return mIsAvailable;
265        }
266    }
267
268    /**
269     * Sets if the network is available, ie, if the connectivity is possible.
270     * @param isAvailable the new availability value.
271     *
272     * @hide
273     */
274    public void setIsAvailable(boolean isAvailable) {
275        synchronized (this) {
276            mIsAvailable = isAvailable;
277        }
278    }
279
280    /**
281     * Indicates whether the current attempt to connect to the network
282     * resulted from the ConnectivityManager trying to fail over to this
283     * network following a disconnect from another network.
284     * @return {@code true} if this is a failover attempt, {@code false}
285     * otherwise.
286     */
287    public boolean isFailover() {
288        synchronized (this) {
289            return mIsFailover;
290        }
291    }
292
293    /**
294     * Set the failover boolean.
295     * @param isFailover {@code true} to mark the current connection attempt
296     * as a failover.
297     * @hide
298     */
299    public void setFailover(boolean isFailover) {
300        synchronized (this) {
301            mIsFailover = isFailover;
302        }
303    }
304
305    /**
306     * Indicates whether the device is currently roaming on this network.
307     * When {@code true}, it suggests that use of data on this network
308     * may incur extra costs.
309     * @return {@code true} if roaming is in effect, {@code false} otherwise.
310     */
311    public boolean isRoaming() {
312        synchronized (this) {
313            return mIsRoaming;
314        }
315    }
316
317    /** {@hide} */
318    @VisibleForTesting
319    public void setRoaming(boolean isRoaming) {
320        synchronized (this) {
321            mIsRoaming = isRoaming;
322        }
323    }
324
325    /**
326     * Reports the current coarse-grained state of the network.
327     * @return the coarse-grained state
328     */
329    public State getState() {
330        synchronized (this) {
331            return mState;
332        }
333    }
334
335    /**
336     * Reports the current fine-grained state of the network.
337     * @return the fine-grained state
338     */
339    public DetailedState getDetailedState() {
340        synchronized (this) {
341            return mDetailedState;
342        }
343    }
344
345    /**
346     * Sets the fine-grained state of the network.
347     * @param detailedState the {@link DetailedState}.
348     * @param reason a {@code String} indicating the reason for the state change,
349     * if one was supplied. May be {@code null}.
350     * @param extraInfo an optional {@code String} providing addditional network state
351     * information passed up from the lower networking layers.
352     * @hide
353     */
354    public void setDetailedState(DetailedState detailedState, String reason, String extraInfo) {
355        synchronized (this) {
356            this.mDetailedState = detailedState;
357            this.mState = stateMap.get(detailedState);
358            this.mReason = reason;
359            this.mExtraInfo = extraInfo;
360        }
361    }
362
363    /**
364     * Set the extraInfo field.
365     * @param extraInfo an optional {@code String} providing addditional network state
366     * information passed up from the lower networking layers.
367     * @hide
368     */
369    public void setExtraInfo(String extraInfo) {
370        synchronized (this) {
371            this.mExtraInfo = extraInfo;
372        }
373    }
374
375    /**
376     * Report the reason an attempt to establish connectivity failed,
377     * if one is available.
378     * @return the reason for failure, or null if not available
379     */
380    public String getReason() {
381        synchronized (this) {
382            return mReason;
383        }
384    }
385
386    /**
387     * Report the extra information about the network state, if any was
388     * provided by the lower networking layers.,
389     * if one is available.
390     * @return the extra information, or null if not available
391     */
392    public String getExtraInfo() {
393        synchronized (this) {
394            return mExtraInfo;
395        }
396    }
397
398    @Override
399    public String toString() {
400        synchronized (this) {
401            StringBuilder builder = new StringBuilder("NetworkInfo: ");
402            builder.append("type: ").append(getTypeName()).append("[").append(getSubtypeName()).
403            append("], state: ").append(mState).append("/").append(mDetailedState).
404            append(", reason: ").append(mReason == null ? "(unspecified)" : mReason).
405            append(", extra: ").append(mExtraInfo == null ? "(none)" : mExtraInfo).
406            append(", roaming: ").append(mIsRoaming).
407            append(", failover: ").append(mIsFailover).
408            append(", isAvailable: ").append(mIsAvailable);
409            return builder.toString();
410        }
411    }
412
413    /**
414     * Implement the Parcelable interface
415     * @hide
416     */
417    public int describeContents() {
418        return 0;
419    }
420
421    /**
422     * Implement the Parcelable interface.
423     * @hide
424     */
425    public void writeToParcel(Parcel dest, int flags) {
426        synchronized (this) {
427            dest.writeInt(mNetworkType);
428            dest.writeInt(mSubtype);
429            dest.writeString(mTypeName);
430            dest.writeString(mSubtypeName);
431            dest.writeString(mState.name());
432            dest.writeString(mDetailedState.name());
433            dest.writeInt(mIsFailover ? 1 : 0);
434            dest.writeInt(mIsAvailable ? 1 : 0);
435            dest.writeInt(mIsRoaming ? 1 : 0);
436            dest.writeString(mReason);
437            dest.writeString(mExtraInfo);
438        }
439    }
440
441    /**
442     * Implement the Parcelable interface.
443     * @hide
444     */
445    public static final Creator<NetworkInfo> CREATOR =
446        new Creator<NetworkInfo>() {
447            public NetworkInfo createFromParcel(Parcel in) {
448                int netType = in.readInt();
449                int subtype = in.readInt();
450                String typeName = in.readString();
451                String subtypeName = in.readString();
452                NetworkInfo netInfo = new NetworkInfo(netType, subtype, typeName, subtypeName);
453                netInfo.mState = State.valueOf(in.readString());
454                netInfo.mDetailedState = DetailedState.valueOf(in.readString());
455                netInfo.mIsFailover = in.readInt() != 0;
456                netInfo.mIsAvailable = in.readInt() != 0;
457                netInfo.mIsRoaming = in.readInt() != 0;
458                netInfo.mReason = in.readString();
459                netInfo.mExtraInfo = in.readString();
460                return netInfo;
461            }
462
463            public NetworkInfo[] newArray(int size) {
464                return new NetworkInfo[size];
465            }
466        };
467}
468