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.wifi;
18 
19 import android.annotation.IntRange;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.compat.annotation.UnsupportedAppUsage;
23 import android.net.NetworkInfo.DetailedState;
24 import android.net.NetworkUtils;
25 import android.os.Build;
26 import android.os.Parcel;
27 import android.os.Parcelable;
28 import android.text.TextUtils;
29 
30 import java.net.Inet4Address;
31 import java.net.InetAddress;
32 import java.net.UnknownHostException;
33 import java.util.EnumMap;
34 import java.util.Locale;
35 
36 /**
37  * Describes the state of any Wifi connection that is active or
38  * is in the process of being set up.
39  */
40 public class WifiInfo implements Parcelable {
41     private static final String TAG = "WifiInfo";
42     /**
43      * This is the map described in the Javadoc comment above. The positions
44      * of the elements of the array must correspond to the ordinal values
45      * of <code>DetailedState</code>.
46      */
47     private static final EnumMap<SupplicantState, DetailedState> stateMap =
48             new EnumMap<SupplicantState, DetailedState>(SupplicantState.class);
49 
50     /**
51      * Default MAC address reported to a client that does not have the
52      * android.permission.LOCAL_MAC_ADDRESS permission.
53      *
54      * @hide
55      */
56     @UnsupportedAppUsage
57     public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00";
58 
59     static {
stateMap.put(SupplicantState.DISCONNECTED, DetailedState.DISCONNECTED)60         stateMap.put(SupplicantState.DISCONNECTED, DetailedState.DISCONNECTED);
stateMap.put(SupplicantState.INTERFACE_DISABLED, DetailedState.DISCONNECTED)61         stateMap.put(SupplicantState.INTERFACE_DISABLED, DetailedState.DISCONNECTED);
stateMap.put(SupplicantState.INACTIVE, DetailedState.IDLE)62         stateMap.put(SupplicantState.INACTIVE, DetailedState.IDLE);
stateMap.put(SupplicantState.SCANNING, DetailedState.SCANNING)63         stateMap.put(SupplicantState.SCANNING, DetailedState.SCANNING);
stateMap.put(SupplicantState.AUTHENTICATING, DetailedState.CONNECTING)64         stateMap.put(SupplicantState.AUTHENTICATING, DetailedState.CONNECTING);
stateMap.put(SupplicantState.ASSOCIATING, DetailedState.CONNECTING)65         stateMap.put(SupplicantState.ASSOCIATING, DetailedState.CONNECTING);
stateMap.put(SupplicantState.ASSOCIATED, DetailedState.CONNECTING)66         stateMap.put(SupplicantState.ASSOCIATED, DetailedState.CONNECTING);
stateMap.put(SupplicantState.FOUR_WAY_HANDSHAKE, DetailedState.AUTHENTICATING)67         stateMap.put(SupplicantState.FOUR_WAY_HANDSHAKE, DetailedState.AUTHENTICATING);
stateMap.put(SupplicantState.GROUP_HANDSHAKE, DetailedState.AUTHENTICATING)68         stateMap.put(SupplicantState.GROUP_HANDSHAKE, DetailedState.AUTHENTICATING);
stateMap.put(SupplicantState.COMPLETED, DetailedState.OBTAINING_IPADDR)69         stateMap.put(SupplicantState.COMPLETED, DetailedState.OBTAINING_IPADDR);
stateMap.put(SupplicantState.DORMANT, DetailedState.DISCONNECTED)70         stateMap.put(SupplicantState.DORMANT, DetailedState.DISCONNECTED);
stateMap.put(SupplicantState.UNINITIALIZED, DetailedState.IDLE)71         stateMap.put(SupplicantState.UNINITIALIZED, DetailedState.IDLE);
stateMap.put(SupplicantState.INVALID, DetailedState.FAILED)72         stateMap.put(SupplicantState.INVALID, DetailedState.FAILED);
73     }
74 
75     private SupplicantState mSupplicantState;
76     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
77     private String mBSSID;
78     @UnsupportedAppUsage
79     private WifiSsid mWifiSsid;
80     private int mNetworkId;
81 
82     /** @hide **/
83     @UnsupportedAppUsage
84     public static final int INVALID_RSSI = -127;
85 
86     /** @hide **/
87     public static final int MIN_RSSI = -126;
88 
89     /** @hide **/
90     public static final int MAX_RSSI = 200;
91 
92 
93     /**
94      * Received Signal Strength Indicator
95      */
96     private int mRssi;
97 
98     /**
99      * The unit in which links speeds are expressed.
100      */
101     public static final String LINK_SPEED_UNITS = "Mbps";
102     private int mLinkSpeed;
103 
104     /**
105      * Constant for unknown link speed.
106      */
107     public static final int LINK_SPEED_UNKNOWN = -1;
108 
109     /**
110      * Tx(transmit) Link speed in Mbps
111      */
112     private int mTxLinkSpeed;
113 
114     /**
115      * Rx(receive) Link speed in Mbps
116      */
117     private int mRxLinkSpeed;
118 
119     /**
120      * Frequency in MHz
121      */
122     public static final String FREQUENCY_UNITS = "MHz";
123     private int mFrequency;
124 
125     @UnsupportedAppUsage
126     private InetAddress mIpAddress;
127     @UnsupportedAppUsage
128     private String mMacAddress = DEFAULT_MAC_ADDRESS;
129 
130     /**
131      * Whether the network is ephemeral or not.
132      */
133     private boolean mEphemeral;
134 
135     /**
136      * Whether the network is trusted or not.
137      */
138     private boolean mTrusted;
139 
140     /**
141      * OSU (Online Sign Up) AP for Passpoint R2.
142      */
143     private boolean mOsuAp;
144 
145     /**
146      * Fully qualified domain name of a Passpoint configuration
147      */
148     private String mFqdn;
149 
150     /**
151      * Name of Passpoint credential provider
152      */
153     private String mProviderFriendlyName;
154 
155     /**
156      * If connected to a network suggestion or specifier, store the package name of the app,
157      * else null.
158      */
159     private String mNetworkSuggestionOrSpecifierPackageName;
160 
161     /**
162      * Running total count of lost (not ACKed) transmitted unicast data packets.
163      * @hide
164      */
165     public long txBad;
166     /**
167      * Running total count of transmitted unicast data retry packets.
168      * @hide
169      */
170     public long txRetries;
171     /**
172      * Running total count of successfully transmitted (ACKed) unicast data packets.
173      * @hide
174      */
175     public long txSuccess;
176     /**
177      * Running total count of received unicast data packets.
178      * @hide
179      */
180     public long rxSuccess;
181 
182     /**
183      * Average rate of lost transmitted packets, in units of packets per second.
184      * @hide
185      */
186     public double txBadRate;
187     /**
188      * Average rate of transmitted retry packets, in units of packets per second.
189      * @hide
190      */
191     public double txRetriesRate;
192     /**
193      * Average rate of successfully transmitted unicast packets, in units of packets per second.
194      * @hide
195      */
196     public double txSuccessRate;
197     /**
198      * Average rate of received unicast data packets, in units of packets per second.
199      * @hide
200      */
201     public double rxSuccessRate;
202 
203     /**
204      * @hide
205      */
206     @UnsupportedAppUsage
207     public int score;
208 
209     /**
210      * Flag indicating that AP has hinted that upstream connection is metered,
211      * and sensitive to heavy data transfers.
212      */
213     private boolean mMeteredHint;
214 
215     /** @hide */
216     @UnsupportedAppUsage
WifiInfo()217     public WifiInfo() {
218         mWifiSsid = null;
219         mBSSID = null;
220         mNetworkId = -1;
221         mSupplicantState = SupplicantState.UNINITIALIZED;
222         mRssi = INVALID_RSSI;
223         mLinkSpeed = LINK_SPEED_UNKNOWN;
224         mFrequency = -1;
225     }
226 
227     /** @hide */
reset()228     public void reset() {
229         setInetAddress(null);
230         setBSSID(null);
231         setSSID(null);
232         setNetworkId(-1);
233         setRssi(INVALID_RSSI);
234         setLinkSpeed(LINK_SPEED_UNKNOWN);
235         setTxLinkSpeedMbps(LINK_SPEED_UNKNOWN);
236         setRxLinkSpeedMbps(LINK_SPEED_UNKNOWN);
237         setFrequency(-1);
238         setMeteredHint(false);
239         setEphemeral(false);
240         setOsuAp(false);
241         setNetworkSuggestionOrSpecifierPackageName(null);
242         setFQDN(null);
243         setProviderFriendlyName(null);
244         txBad = 0;
245         txSuccess = 0;
246         rxSuccess = 0;
247         txRetries = 0;
248         txBadRate = 0;
249         txSuccessRate = 0;
250         rxSuccessRate = 0;
251         txRetriesRate = 0;
252         score = 0;
253     }
254 
255     /**
256      * Copy constructor
257      * @hide
258      */
WifiInfo(WifiInfo source)259     public WifiInfo(WifiInfo source) {
260         if (source != null) {
261             mSupplicantState = source.mSupplicantState;
262             mBSSID = source.mBSSID;
263             mWifiSsid = source.mWifiSsid;
264             mNetworkId = source.mNetworkId;
265             mRssi = source.mRssi;
266             mLinkSpeed = source.mLinkSpeed;
267             mTxLinkSpeed = source.mTxLinkSpeed;
268             mRxLinkSpeed = source.mRxLinkSpeed;
269             mFrequency = source.mFrequency;
270             mIpAddress = source.mIpAddress;
271             mMacAddress = source.mMacAddress;
272             mMeteredHint = source.mMeteredHint;
273             mEphemeral = source.mEphemeral;
274             mTrusted = source.mTrusted;
275             mNetworkSuggestionOrSpecifierPackageName =
276                     source.mNetworkSuggestionOrSpecifierPackageName;
277             mOsuAp = source.mOsuAp;
278             mFqdn = source.mFqdn;
279             mProviderFriendlyName = source.mProviderFriendlyName;
280             txBad = source.txBad;
281             txRetries = source.txRetries;
282             txSuccess = source.txSuccess;
283             rxSuccess = source.rxSuccess;
284             txBadRate = source.txBadRate;
285             txRetriesRate = source.txRetriesRate;
286             txSuccessRate = source.txSuccessRate;
287             rxSuccessRate = source.rxSuccessRate;
288             score = source.score;
289         }
290     }
291 
292     /** @hide */
setSSID(WifiSsid wifiSsid)293     public void setSSID(WifiSsid wifiSsid) {
294         mWifiSsid = wifiSsid;
295     }
296 
297     /**
298      * Returns the service set identifier (SSID) of the current 802.11 network.
299      * <p>
300      * If the SSID can be decoded as UTF-8, it will be returned surrounded by double
301      * quotation marks. Otherwise, it is returned as a string of hex digits.
302      * The SSID may be
303      * <lt>&lt;unknown ssid&gt;, if there is no network currently connected or if the caller has
304      * insufficient permissions to access the SSID.<lt>
305      * </p>
306      * <p>
307      * Prior to {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method
308      * always returned the SSID with no quotes around it.
309      * </p>
310      *
311      * @return the SSID.
312      */
getSSID()313     public String getSSID() {
314         if (mWifiSsid != null) {
315             String unicode = mWifiSsid.toString();
316             if (!TextUtils.isEmpty(unicode)) {
317                 return "\"" + unicode + "\"";
318             } else {
319                 String hex = mWifiSsid.getHexString();
320                 return (hex != null) ? hex : WifiSsid.NONE;
321             }
322         }
323         return WifiSsid.NONE;
324     }
325 
326     /** @hide */
327     @UnsupportedAppUsage
getWifiSsid()328     public WifiSsid getWifiSsid() {
329         return mWifiSsid;
330     }
331 
332     /** @hide */
333     @UnsupportedAppUsage
setBSSID(String BSSID)334     public void setBSSID(String BSSID) {
335         mBSSID = BSSID;
336     }
337 
338     /**
339      * Return the basic service set identifier (BSSID) of the current access point.
340      * <p>
341      * The BSSID may be
342      * <lt>{@code null}, if there is no network currently connected.</lt>
343      * <lt>{@code "02:00:00:00:00:00"}, if the caller has insufficient permissions to access the
344      * BSSID.<lt>
345      * </p>
346      *
347      * @return the BSSID, in the form of a six-byte MAC address: {@code XX:XX:XX:XX:XX:XX}
348      */
getBSSID()349     public String getBSSID() {
350         return mBSSID;
351     }
352 
353     /**
354      * Returns the received signal strength indicator of the current 802.11
355      * network, in dBm.
356      *
357      * <p>Use {@link android.net.wifi.WifiManager#calculateSignalLevel} to convert this number into
358      * an absolute signal level which can be displayed to a user.
359      *
360      * @return the RSSI.
361      */
getRssi()362     public int getRssi() {
363         return mRssi;
364     }
365 
366     /** @hide */
367     @UnsupportedAppUsage
setRssi(int rssi)368     public void setRssi(int rssi) {
369         if (rssi < INVALID_RSSI)
370             rssi = INVALID_RSSI;
371         if (rssi > MAX_RSSI)
372             rssi = MAX_RSSI;
373         mRssi = rssi;
374     }
375 
376     /**
377      * Returns the current link speed in {@link #LINK_SPEED_UNITS}.
378      * @return the link speed or {@link #LINK_SPEED_UNKNOWN} if link speed is unknown.
379      * @see #LINK_SPEED_UNITS
380      * @see #LINK_SPEED_UNKNOWN
381      */
getLinkSpeed()382     public int getLinkSpeed() {
383         return mLinkSpeed;
384     }
385 
386     /** @hide */
387     @UnsupportedAppUsage
setLinkSpeed(int linkSpeed)388     public void setLinkSpeed(int linkSpeed) {
389         mLinkSpeed = linkSpeed;
390     }
391 
392     /**
393      * Returns the current transmit link speed in Mbps.
394      * @return the Tx link speed or {@link #LINK_SPEED_UNKNOWN} if link speed is unknown.
395      * @see #LINK_SPEED_UNKNOWN
396      */
397     @IntRange(from = -1)
getTxLinkSpeedMbps()398     public int getTxLinkSpeedMbps() {
399         return mTxLinkSpeed;
400     }
401 
402     /**
403      * Update the last transmitted packet bit rate in Mbps.
404      * @hide
405      */
setTxLinkSpeedMbps(int txLinkSpeed)406     public void setTxLinkSpeedMbps(int txLinkSpeed) {
407         mTxLinkSpeed = txLinkSpeed;
408     }
409 
410     /**
411      * Returns the current receive link speed in Mbps.
412      * @return the Rx link speed or {@link #LINK_SPEED_UNKNOWN} if link speed is unknown.
413      * @see #LINK_SPEED_UNKNOWN
414      */
415     @IntRange(from = -1)
getRxLinkSpeedMbps()416     public int getRxLinkSpeedMbps() {
417         return mRxLinkSpeed;
418     }
419 
420     /**
421      * Update the last received packet bit rate in Mbps.
422      * @hide
423      */
setRxLinkSpeedMbps(int rxLinkSpeed)424     public void setRxLinkSpeedMbps(int rxLinkSpeed) {
425         mRxLinkSpeed = rxLinkSpeed;
426     }
427 
428     /**
429      * Returns the current frequency in {@link #FREQUENCY_UNITS}.
430      * @return the frequency.
431      * @see #FREQUENCY_UNITS
432      */
getFrequency()433     public int getFrequency() {
434         return mFrequency;
435     }
436 
437     /** @hide */
setFrequency(int frequency)438     public void setFrequency(int frequency) {
439         this.mFrequency = frequency;
440     }
441 
442     /**
443      * @hide
444      * TODO: makes real freq boundaries
445      */
is24GHz()446     public boolean is24GHz() {
447         return ScanResult.is24GHz(mFrequency);
448     }
449 
450     /**
451      * @hide
452      * TODO: makes real freq boundaries
453      */
454     @UnsupportedAppUsage
is5GHz()455     public boolean is5GHz() {
456         return ScanResult.is5GHz(mFrequency);
457     }
458 
459     /**
460      * Record the MAC address of the WLAN interface
461      * @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form
462      * @hide
463      */
464     @UnsupportedAppUsage
setMacAddress(String macAddress)465     public void setMacAddress(String macAddress) {
466         this.mMacAddress = macAddress;
467     }
468 
getMacAddress()469     public String getMacAddress() {
470         return mMacAddress;
471     }
472 
473     /**
474      * @return true if {@link #getMacAddress()} has a real MAC address.
475      *
476      * @hide
477      */
hasRealMacAddress()478     public boolean hasRealMacAddress() {
479         return mMacAddress != null && !DEFAULT_MAC_ADDRESS.equals(mMacAddress);
480     }
481 
482     /**
483      * Indicates if we've dynamically detected this active network connection as
484      * being metered.
485      *
486      * @see WifiConfiguration#isMetered(WifiConfiguration, WifiInfo)
487      * @hide
488      */
setMeteredHint(boolean meteredHint)489     public void setMeteredHint(boolean meteredHint) {
490         mMeteredHint = meteredHint;
491     }
492 
493     /** {@hide} */
494     @UnsupportedAppUsage
getMeteredHint()495     public boolean getMeteredHint() {
496         return mMeteredHint;
497     }
498 
499     /** {@hide} */
setEphemeral(boolean ephemeral)500     public void setEphemeral(boolean ephemeral) {
501         mEphemeral = ephemeral;
502     }
503 
504     /** {@hide} */
505     @UnsupportedAppUsage
isEphemeral()506     public boolean isEphemeral() {
507         return mEphemeral;
508     }
509 
510     /** {@hide} */
setTrusted(boolean trusted)511     public void setTrusted(boolean trusted) {
512         mTrusted = trusted;
513     }
514 
515     /** {@hide} */
isTrusted()516     public boolean isTrusted() {
517         return mTrusted;
518     }
519 
520     /** {@hide} */
setOsuAp(boolean osuAp)521     public void setOsuAp(boolean osuAp) {
522         mOsuAp = osuAp;
523     }
524 
525     /** {@hide} */
526     @SystemApi
isOsuAp()527     public boolean isOsuAp() {
528         return mOsuAp;
529     }
530 
531     /** {@hide} */
532     @SystemApi
isPasspointAp()533     public boolean isPasspointAp() {
534         return mFqdn != null && mProviderFriendlyName != null;
535     }
536 
537     /** {@hide} */
setFQDN(@ullable String fqdn)538     public void setFQDN(@Nullable String fqdn) {
539         mFqdn = fqdn;
540     }
541 
542     /**
543      * Returns the Fully Qualified Domain Name of the network if it is a Passpoint network.
544      */
getPasspointFqdn()545     public @Nullable String getPasspointFqdn() {
546         return mFqdn;
547     }
548 
549     /** {@hide} */
setProviderFriendlyName(@ullable String providerFriendlyName)550     public void setProviderFriendlyName(@Nullable String providerFriendlyName) {
551         mProviderFriendlyName = providerFriendlyName;
552     }
553 
554     /**
555      * Returns the Provider Friendly Name of the network if it is a Passpoint network.
556      */
getPasspointProviderFriendlyName()557     public @Nullable String getPasspointProviderFriendlyName() {
558         return mProviderFriendlyName;
559     }
560 
561     /** {@hide} */
setNetworkSuggestionOrSpecifierPackageName(@ullable String packageName)562     public void setNetworkSuggestionOrSpecifierPackageName(@Nullable String packageName) {
563         mNetworkSuggestionOrSpecifierPackageName = packageName;
564     }
565 
566     /** {@hide} */
getNetworkSuggestionOrSpecifierPackageName()567     public @Nullable String getNetworkSuggestionOrSpecifierPackageName() {
568         return mNetworkSuggestionOrSpecifierPackageName;
569     }
570 
571 
572     /** @hide */
573     @UnsupportedAppUsage
setNetworkId(int id)574     public void setNetworkId(int id) {
575         mNetworkId = id;
576     }
577 
578     /**
579      * Each configured network has a unique small integer ID, used to identify
580      * the network. This method returns the ID for the currently connected network.
581      * <p>
582      * The networkId may be {@code -1} if there is no currently connected network or if the caller
583      * has insufficient permissions to access the network ID.
584      * </p>
585      *
586      * @return the network ID.
587      */
getNetworkId()588     public int getNetworkId() {
589         return mNetworkId;
590     }
591 
592     /**
593      * Return the detailed state of the supplicant's negotiation with an
594      * access point, in the form of a {@link SupplicantState SupplicantState} object.
595      * @return the current {@link SupplicantState SupplicantState}
596      */
getSupplicantState()597     public SupplicantState getSupplicantState() {
598         return mSupplicantState;
599     }
600 
601     /** @hide */
602     @UnsupportedAppUsage
setSupplicantState(SupplicantState state)603     public void setSupplicantState(SupplicantState state) {
604         mSupplicantState = state;
605     }
606 
607     /** @hide */
setInetAddress(InetAddress address)608     public void setInetAddress(InetAddress address) {
609         mIpAddress = address;
610     }
611 
getIpAddress()612     public int getIpAddress() {
613         int result = 0;
614         if (mIpAddress instanceof Inet4Address) {
615             result = NetworkUtils.inetAddressToInt((Inet4Address)mIpAddress);
616         }
617         return result;
618     }
619 
620     /**
621      * @return {@code true} if this network does not broadcast its SSID, so an
622      * SSID-specific probe request must be used for scans.
623      */
getHiddenSSID()624     public boolean getHiddenSSID() {
625         if (mWifiSsid == null) return false;
626         return mWifiSsid.isHidden();
627     }
628 
629    /**
630      * Map a supplicant state into a fine-grained network connectivity state.
631      * @param suppState the supplicant state
632      * @return the corresponding {@link DetailedState}
633      */
getDetailedStateOf(SupplicantState suppState)634     public static DetailedState getDetailedStateOf(SupplicantState suppState) {
635         return stateMap.get(suppState);
636     }
637 
638     /**
639      * Set the <code>SupplicantState</code> from the string name
640      * of the state.
641      * @param stateName the name of the state, as a <code>String</code> returned
642      * in an event sent by {@code wpa_supplicant}.
643      */
644     @UnsupportedAppUsage
setSupplicantState(String stateName)645     void setSupplicantState(String stateName) {
646         mSupplicantState = valueOf(stateName);
647     }
648 
valueOf(String stateName)649     static SupplicantState valueOf(String stateName) {
650         if ("4WAY_HANDSHAKE".equalsIgnoreCase(stateName))
651             return SupplicantState.FOUR_WAY_HANDSHAKE;
652         else {
653             try {
654                 return SupplicantState.valueOf(stateName.toUpperCase(Locale.ROOT));
655             } catch (IllegalArgumentException e) {
656                 return SupplicantState.INVALID;
657             }
658         }
659     }
660 
661     /**
662      * Remove double quotes (") surrounding a SSID string, if present. Otherwise, return the
663      * string unmodified. Return null if the input string was null.
664      * @hide
665      */
666     @Nullable
667     @SystemApi
sanitizeSsid(@ullable String string)668     public static String sanitizeSsid(@Nullable String string) {
669         return removeDoubleQuotes(string);
670     }
671 
672     /** @hide */
673     @UnsupportedAppUsage
674     @Nullable
removeDoubleQuotes(@ullable String string)675     public static String removeDoubleQuotes(@Nullable String string) {
676         if (string == null) return null;
677         final int length = string.length();
678         if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
679             return string.substring(1, length - 1);
680         }
681         return string;
682     }
683 
684     @Override
toString()685     public String toString() {
686         StringBuffer sb = new StringBuffer();
687         String none = "<none>";
688 
689         sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid)
690                 .append(", BSSID: ").append(mBSSID == null ? none : mBSSID)
691                 .append(", MAC: ").append(mMacAddress == null ? none : mMacAddress)
692                 .append(", Supplicant state: ")
693                 .append(mSupplicantState == null ? none : mSupplicantState)
694                 .append(", RSSI: ").append(mRssi)
695                 .append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS)
696                 .append(", Tx Link speed: ").append(mTxLinkSpeed).append(LINK_SPEED_UNITS)
697                 .append(", Rx Link speed: ").append(mRxLinkSpeed).append(LINK_SPEED_UNITS)
698                 .append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS)
699                 .append(", Net ID: ").append(mNetworkId)
700                 .append(", Metered hint: ").append(mMeteredHint)
701                 .append(", score: ").append(Integer.toString(score));
702         return sb.toString();
703     }
704 
705     /** Implement the Parcelable interface {@hide} */
describeContents()706     public int describeContents() {
707         return 0;
708     }
709 
710     /** Implement the Parcelable interface {@hide} */
writeToParcel(Parcel dest, int flags)711     public void writeToParcel(Parcel dest, int flags) {
712         dest.writeInt(mNetworkId);
713         dest.writeInt(mRssi);
714         dest.writeInt(mLinkSpeed);
715         dest.writeInt(mTxLinkSpeed);
716         dest.writeInt(mRxLinkSpeed);
717         dest.writeInt(mFrequency);
718         if (mIpAddress != null) {
719             dest.writeByte((byte)1);
720             dest.writeByteArray(mIpAddress.getAddress());
721         } else {
722             dest.writeByte((byte)0);
723         }
724         if (mWifiSsid != null) {
725             dest.writeInt(1);
726             mWifiSsid.writeToParcel(dest, flags);
727         } else {
728             dest.writeInt(0);
729         }
730         dest.writeString(mBSSID);
731         dest.writeString(mMacAddress);
732         dest.writeInt(mMeteredHint ? 1 : 0);
733         dest.writeInt(mEphemeral ? 1 : 0);
734         dest.writeInt(mTrusted ? 1 : 0);
735         dest.writeInt(score);
736         dest.writeLong(txSuccess);
737         dest.writeDouble(txSuccessRate);
738         dest.writeLong(txRetries);
739         dest.writeDouble(txRetriesRate);
740         dest.writeLong(txBad);
741         dest.writeDouble(txBadRate);
742         dest.writeLong(rxSuccess);
743         dest.writeDouble(rxSuccessRate);
744         mSupplicantState.writeToParcel(dest, flags);
745         dest.writeInt(mOsuAp ? 1 : 0);
746         dest.writeString(mNetworkSuggestionOrSpecifierPackageName);
747         dest.writeString(mFqdn);
748         dest.writeString(mProviderFriendlyName);
749     }
750 
751     /** Implement the Parcelable interface {@hide} */
752     @UnsupportedAppUsage
753     public static final @android.annotation.NonNull Creator<WifiInfo> CREATOR =
754         new Creator<WifiInfo>() {
755             public WifiInfo createFromParcel(Parcel in) {
756                 WifiInfo info = new WifiInfo();
757                 info.setNetworkId(in.readInt());
758                 info.setRssi(in.readInt());
759                 info.setLinkSpeed(in.readInt());
760                 info.setTxLinkSpeedMbps(in.readInt());
761                 info.setRxLinkSpeedMbps(in.readInt());
762                 info.setFrequency(in.readInt());
763                 if (in.readByte() == 1) {
764                     try {
765                         info.setInetAddress(InetAddress.getByAddress(in.createByteArray()));
766                     } catch (UnknownHostException e) {}
767                 }
768                 if (in.readInt() == 1) {
769                     info.mWifiSsid = WifiSsid.CREATOR.createFromParcel(in);
770                 }
771                 info.mBSSID = in.readString();
772                 info.mMacAddress = in.readString();
773                 info.mMeteredHint = in.readInt() != 0;
774                 info.mEphemeral = in.readInt() != 0;
775                 info.mTrusted = in.readInt() != 0;
776                 info.score = in.readInt();
777                 info.txSuccess = in.readLong();
778                 info.txSuccessRate = in.readDouble();
779                 info.txRetries = in.readLong();
780                 info.txRetriesRate = in.readDouble();
781                 info.txBad = in.readLong();
782                 info.txBadRate = in.readDouble();
783                 info.rxSuccess = in.readLong();
784                 info.rxSuccessRate = in.readDouble();
785                 info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in);
786                 info.mOsuAp = in.readInt() != 0;
787                 info.mNetworkSuggestionOrSpecifierPackageName = in.readString();
788                 info.mFqdn = in.readString();
789                 info.mProviderFriendlyName = in.readString();
790                 return info;
791             }
792 
793             public WifiInfo[] newArray(int size) {
794                 return new WifiInfo[size];
795             }
796         };
797 }
798