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