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