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.SdkConstant;
20 import android.annotation.SdkConstant.SdkConstantType;
21 import android.annotation.SystemApi;
22 import android.content.Context;
23 import android.net.ConnectivityManager;
24 import android.net.ConnectivityManager.NetworkCallback;
25 import android.net.DhcpInfo;
26 import android.net.Network;
27 import android.net.NetworkCapabilities;
28 import android.net.NetworkRequest;
29 import android.net.wifi.ScanSettings;
30 import android.net.wifi.WifiChannel;
31 import android.os.Binder;
32 import android.os.Build;
33 import android.os.IBinder;
34 import android.os.Handler;
35 import android.os.HandlerThread;
36 import android.os.Looper;
37 import android.os.Message;
38 import android.os.RemoteException;
39 import android.os.WorkSource;
40 import android.os.Messenger;
41 import android.util.Log;
42 import android.util.SparseArray;
43 
44 import java.net.InetAddress;
45 import java.util.concurrent.CountDownLatch;
46 
47 import com.android.internal.annotations.GuardedBy;
48 import com.android.internal.util.AsyncChannel;
49 import com.android.internal.util.Protocol;
50 
51 import java.util.List;
52 
53 /**
54  * This class provides the primary API for managing all aspects of Wi-Fi
55  * connectivity. Get an instance of this class by calling
56  * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.WIFI_SERVICE)}.
57 
58  * It deals with several categories of items:
59  * <ul>
60  * <li>The list of configured networks. The list can be viewed and updated,
61  * and attributes of individual entries can be modified.</li>
62  * <li>The currently active Wi-Fi network, if any. Connectivity can be
63  * established or torn down, and dynamic information about the state of
64  * the network can be queried.</li>
65  * <li>Results of access point scans, containing enough information to
66  * make decisions about what access point to connect to.</li>
67  * <li>It defines the names of various Intent actions that are broadcast
68  * upon any sort of change in Wi-Fi state.
69  * </ul>
70  * This is the API to use when performing Wi-Fi specific operations. To
71  * perform operations that pertain to network connectivity at an abstract
72  * level, use {@link android.net.ConnectivityManager}.
73  */
74 public class WifiManager {
75 
76     private static final String TAG = "WifiManager";
77     // Supplicant error codes:
78     /**
79      * The error code if there was a problem authenticating.
80      */
81     public static final int ERROR_AUTHENTICATING = 1;
82 
83     /**
84      * Broadcast intent action indicating whether Wi-Fi scanning is allowed currently
85      * @hide
86      */
87     public static final String WIFI_SCAN_AVAILABLE = "wifi_scan_available";
88 
89     /**
90      * Extra int indicating scan availability, WIFI_STATE_ENABLED and WIFI_STATE_DISABLED
91      * @hide
92      */
93     public static final String EXTRA_SCAN_AVAILABLE = "scan_enabled";
94 
95     /**
96      * Broadcast intent action indicating that the credential of a Wi-Fi network
97      * has been changed. One extra provides the ssid of the network. Another
98      * extra provides the event type, whether the credential is saved or forgot.
99      * @hide
100      */
101     @SystemApi
102     public static final String WIFI_CREDENTIAL_CHANGED_ACTION =
103             "android.net.wifi.WIFI_CREDENTIAL_CHANGED";
104     /** @hide */
105     @SystemApi
106     public static final String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
107     /** @hide */
108     @SystemApi
109     public static final String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
110     /** @hide */
111     @SystemApi
112     public static final int WIFI_CREDENTIAL_SAVED = 0;
113     /** @hide */
114     @SystemApi
115     public static final int WIFI_CREDENTIAL_FORGOT = 1;
116 
117     /**
118      * Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
119      * enabling, disabling, or unknown. One extra provides this state as an int.
120      * Another extra provides the previous state, if available.
121      *
122      * @see #EXTRA_WIFI_STATE
123      * @see #EXTRA_PREVIOUS_WIFI_STATE
124      */
125     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
126     public static final String WIFI_STATE_CHANGED_ACTION =
127         "android.net.wifi.WIFI_STATE_CHANGED";
128     /**
129      * The lookup key for an int that indicates whether Wi-Fi is enabled,
130      * disabled, enabling, disabling, or unknown.  Retrieve it with
131      * {@link android.content.Intent#getIntExtra(String,int)}.
132      *
133      * @see #WIFI_STATE_DISABLED
134      * @see #WIFI_STATE_DISABLING
135      * @see #WIFI_STATE_ENABLED
136      * @see #WIFI_STATE_ENABLING
137      * @see #WIFI_STATE_UNKNOWN
138      */
139     public static final String EXTRA_WIFI_STATE = "wifi_state";
140     /**
141      * The previous Wi-Fi state.
142      *
143      * @see #EXTRA_WIFI_STATE
144      */
145     public static final String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
146 
147     /**
148      * Wi-Fi is currently being disabled. The state will change to {@link #WIFI_STATE_DISABLED} if
149      * it finishes successfully.
150      *
151      * @see #WIFI_STATE_CHANGED_ACTION
152      * @see #getWifiState()
153      */
154     public static final int WIFI_STATE_DISABLING = 0;
155     /**
156      * Wi-Fi is disabled.
157      *
158      * @see #WIFI_STATE_CHANGED_ACTION
159      * @see #getWifiState()
160      */
161     public static final int WIFI_STATE_DISABLED = 1;
162     /**
163      * Wi-Fi is currently being enabled. The state will change to {@link #WIFI_STATE_ENABLED} if
164      * it finishes successfully.
165      *
166      * @see #WIFI_STATE_CHANGED_ACTION
167      * @see #getWifiState()
168      */
169     public static final int WIFI_STATE_ENABLING = 2;
170     /**
171      * Wi-Fi is enabled.
172      *
173      * @see #WIFI_STATE_CHANGED_ACTION
174      * @see #getWifiState()
175      */
176     public static final int WIFI_STATE_ENABLED = 3;
177     /**
178      * Wi-Fi is in an unknown state. This state will occur when an error happens while enabling
179      * or disabling.
180      *
181      * @see #WIFI_STATE_CHANGED_ACTION
182      * @see #getWifiState()
183      */
184     public static final int WIFI_STATE_UNKNOWN = 4;
185 
186     /**
187      * Broadcast intent action indicating that Wi-Fi AP has been enabled, disabled,
188      * enabling, disabling, or failed.
189      *
190      * @hide
191      */
192     public static final String WIFI_AP_STATE_CHANGED_ACTION =
193         "android.net.wifi.WIFI_AP_STATE_CHANGED";
194 
195     /**
196      * The lookup key for an int that indicates whether Wi-Fi AP is enabled,
197      * disabled, enabling, disabling, or failed.  Retrieve it with
198      * {@link android.content.Intent#getIntExtra(String,int)}.
199      *
200      * @see #WIFI_AP_STATE_DISABLED
201      * @see #WIFI_AP_STATE_DISABLING
202      * @see #WIFI_AP_STATE_ENABLED
203      * @see #WIFI_AP_STATE_ENABLING
204      * @see #WIFI_AP_STATE_FAILED
205      *
206      * @hide
207      */
208     public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
209 
210     /**
211      * The look up key for an int that indicates why softAP started failed
212      * currently support general and no_channel
213      * @see #SAP_START_FAILURE_GENERAL
214      * @see #SAP_START_FAILURE_NO_CHANNEL
215      *
216      * @hide
217      */
218     public static final String EXTRA_WIFI_AP_FAILURE_REASON = "wifi_ap_error_code";
219     /**
220      * The previous Wi-Fi state.
221      *
222      * @see #EXTRA_WIFI_AP_STATE
223      *
224      * @hide
225      */
226     public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
227     /**
228      * Wi-Fi AP is currently being disabled. The state will change to
229      * {@link #WIFI_AP_STATE_DISABLED} if it finishes successfully.
230      *
231      * @see #WIFI_AP_STATE_CHANGED_ACTION
232      * @see #getWifiApState()
233      *
234      * @hide
235      */
236     public static final int WIFI_AP_STATE_DISABLING = 10;
237     /**
238      * Wi-Fi AP is disabled.
239      *
240      * @see #WIFI_AP_STATE_CHANGED_ACTION
241      * @see #getWifiState()
242      *
243      * @hide
244      */
245     public static final int WIFI_AP_STATE_DISABLED = 11;
246     /**
247      * Wi-Fi AP is currently being enabled. The state will change to
248      * {@link #WIFI_AP_STATE_ENABLED} if it finishes successfully.
249      *
250      * @see #WIFI_AP_STATE_CHANGED_ACTION
251      * @see #getWifiApState()
252      *
253      * @hide
254      */
255     public static final int WIFI_AP_STATE_ENABLING = 12;
256     /**
257      * Wi-Fi AP is enabled.
258      *
259      * @see #WIFI_AP_STATE_CHANGED_ACTION
260      * @see #getWifiApState()
261      *
262      * @hide
263      */
264     public static final int WIFI_AP_STATE_ENABLED = 13;
265     /**
266      * Wi-Fi AP is in a failed state. This state will occur when an error occurs during
267      * enabling or disabling
268      *
269      * @see #WIFI_AP_STATE_CHANGED_ACTION
270      * @see #getWifiApState()
271      *
272      * @hide
273      */
274     public static final int WIFI_AP_STATE_FAILED = 14;
275 
276     /**
277      *  If WIFI AP start failed, this reason code means there is no legal channel exists on
278      *  user selected band by regulatory
279      *
280      *  @hide
281      */
282     public static final int SAP_START_FAILURE_GENERAL= 0;
283 
284     /**
285      *  All other reason for AP start failed besides SAP_START_FAILURE_GENERAL
286      *
287      *  @hide
288      */
289     public static final int SAP_START_FAILURE_NO_CHANNEL = 1;
290     /**
291      * Broadcast intent action indicating that a connection to the supplicant has
292      * been established (and it is now possible
293      * to perform Wi-Fi operations) or the connection to the supplicant has been
294      * lost. One extra provides the connection state as a boolean, where {@code true}
295      * means CONNECTED.
296      * @see #EXTRA_SUPPLICANT_CONNECTED
297      */
298     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
299     public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION =
300         "android.net.wifi.supplicant.CONNECTION_CHANGE";
301     /**
302      * The lookup key for a boolean that indicates whether a connection to
303      * the supplicant daemon has been gained or lost. {@code true} means
304      * a connection now exists.
305      * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
306      */
307     public static final String EXTRA_SUPPLICANT_CONNECTED = "connected";
308     /**
309      * Broadcast intent action indicating that the state of Wi-Fi connectivity
310      * has changed. One extra provides the new state
311      * in the form of a {@link android.net.NetworkInfo} object. If the new
312      * state is CONNECTED, additional extras may provide the BSSID and WifiInfo of
313      * the access point.
314      * as a {@code String}.
315      * @see #EXTRA_NETWORK_INFO
316      * @see #EXTRA_BSSID
317      * @see #EXTRA_WIFI_INFO
318      */
319     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
320     public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
321     /**
322      * The lookup key for a {@link android.net.NetworkInfo} object associated with the
323      * Wi-Fi network. Retrieve with
324      * {@link android.content.Intent#getParcelableExtra(String)}.
325      */
326     public static final String EXTRA_NETWORK_INFO = "networkInfo";
327     /**
328      * The lookup key for a String giving the BSSID of the access point to which
329      * we are connected. Only present when the new state is CONNECTED.
330      * Retrieve with
331      * {@link android.content.Intent#getStringExtra(String)}.
332      */
333     public static final String EXTRA_BSSID = "bssid";
334     /**
335      * The lookup key for a {@link android.net.wifi.WifiInfo} object giving the
336      * information about the access point to which we are connected. Only present
337      * when the new state is CONNECTED.  Retrieve with
338      * {@link android.content.Intent#getParcelableExtra(String)}.
339      */
340     public static final String EXTRA_WIFI_INFO = "wifiInfo";
341     /**
342      * Broadcast intent action indicating that the state of establishing a connection to
343      * an access point has changed.One extra provides the new
344      * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and
345      * is not generally the most useful thing to look at if you are just interested in
346      * the overall state of connectivity.
347      * @see #EXTRA_NEW_STATE
348      * @see #EXTRA_SUPPLICANT_ERROR
349      */
350     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
351     public static final String SUPPLICANT_STATE_CHANGED_ACTION =
352         "android.net.wifi.supplicant.STATE_CHANGE";
353     /**
354      * The lookup key for a {@link SupplicantState} describing the new state
355      * Retrieve with
356      * {@link android.content.Intent#getParcelableExtra(String)}.
357      */
358     public static final String EXTRA_NEW_STATE = "newState";
359 
360     /**
361      * The lookup key for a {@link SupplicantState} describing the supplicant
362      * error code if any
363      * Retrieve with
364      * {@link android.content.Intent#getIntExtra(String, int)}.
365      * @see #ERROR_AUTHENTICATING
366      */
367     public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError";
368 
369     /**
370      * Broadcast intent action indicating that the configured networks changed.
371      * This can be as a result of adding/updating/deleting a network. If
372      * {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is set to true the new configuration
373      * can be retreived with the {@link #EXTRA_WIFI_CONFIGURATION} extra. If multiple
374      * Wi-Fi configurations changed, {@link #EXTRA_WIFI_CONFIGURATION} will not be present.
375      * @hide
376      */
377     @SystemApi
378     public static final String CONFIGURED_NETWORKS_CHANGED_ACTION =
379         "android.net.wifi.CONFIGURED_NETWORKS_CHANGE";
380     /**
381      * The lookup key for a (@link android.net.wifi.WifiConfiguration} object representing
382      * the changed Wi-Fi configuration when the {@link #CONFIGURED_NETWORKS_CHANGED_ACTION}
383      * broadcast is sent.
384      * @hide
385      */
386     @SystemApi
387     public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
388     /**
389      * Multiple network configurations have changed.
390      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
391      *
392      * @hide
393      */
394     @SystemApi
395     public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
396     /**
397      * The lookup key for an integer indicating the reason a Wi-Fi network configuration
398      * has changed. Only present if {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is {@code false}
399      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
400      * @hide
401      */
402     @SystemApi
403     public static final String EXTRA_CHANGE_REASON = "changeReason";
404     /**
405      * The configuration is new and was added.
406      * @hide
407      */
408     @SystemApi
409     public static final int CHANGE_REASON_ADDED = 0;
410     /**
411      * The configuration was removed and is no longer present in the system's list of
412      * configured networks.
413      * @hide
414      */
415     @SystemApi
416     public static final int CHANGE_REASON_REMOVED = 1;
417     /**
418      * The configuration has changed as a result of explicit action or because the system
419      * took an automated action such as disabling a malfunctioning configuration.
420      * @hide
421      */
422     @SystemApi
423     public static final int CHANGE_REASON_CONFIG_CHANGE = 2;
424     /**
425      * An access point scan has completed, and results are available from the supplicant.
426      * Call {@link #getScanResults()} to obtain the results. {@link #EXTRA_RESULTS_UPDATED}
427      * indicates if the scan was completed successfully.
428      */
429     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
430     public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
431 
432     /**
433      * Lookup key for a {@code boolean} representing the result of previous {@link #startScan}
434      * operation, reported with {@link #SCAN_RESULTS_AVAILABLE_ACTION}.
435      * @return true scan was successful, results are updated
436      * @return false scan was not successful, results haven't been updated since previous scan
437      */
438     public static final String EXTRA_RESULTS_UPDATED = "resultsUpdated";
439 
440     /**
441      * A batch of access point scans has been completed and the results areavailable.
442      * Call {@link #getBatchedScanResults()} to obtain the results.
443      * @hide pending review
444      */
445     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
446     public static final String BATCHED_SCAN_RESULTS_AVAILABLE_ACTION =
447             "android.net.wifi.BATCHED_RESULTS";
448     /**
449      * The RSSI (signal strength) has changed.
450      * @see #EXTRA_NEW_RSSI
451      */
452     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
453     public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
454     /**
455      * The lookup key for an {@code int} giving the new RSSI in dBm.
456      */
457     public static final String EXTRA_NEW_RSSI = "newRssi";
458 
459     /**
460      * Broadcast intent action indicating that the link configuration
461      * changed on wifi.
462      * @hide
463      */
464     public static final String LINK_CONFIGURATION_CHANGED_ACTION =
465         "android.net.wifi.LINK_CONFIGURATION_CHANGED";
466 
467     /**
468      * The lookup key for a {@link android.net.LinkProperties} object associated with the
469      * Wi-Fi network. Retrieve with
470      * {@link android.content.Intent#getParcelableExtra(String)}.
471      * @hide
472      */
473     public static final String EXTRA_LINK_PROPERTIES = "linkProperties";
474 
475     /**
476      * The lookup key for a {@link android.net.NetworkCapabilities} object associated with the
477      * Wi-Fi network. Retrieve with
478      * {@link android.content.Intent#getParcelableExtra(String)}.
479      * @hide
480      */
481     public static final String EXTRA_NETWORK_CAPABILITIES = "networkCapabilities";
482 
483     /**
484      * The network IDs of the configured networks could have changed.
485      */
486     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
487     public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
488 
489     /**
490      * Activity Action: Show a system activity that allows the user to enable
491      * scans to be available even with Wi-Fi turned off.
492      *
493      * <p>Notification of the result of this activity is posted using the
494      * {@link android.app.Activity#onActivityResult} callback. The
495      * <code>resultCode</code>
496      * will be {@link android.app.Activity#RESULT_OK} if scan always mode has
497      * been turned on or {@link android.app.Activity#RESULT_CANCELED} if the user
498      * has rejected the request or an error has occurred.
499      */
500     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
501     public static final String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE =
502             "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
503 
504     /**
505      * Activity Action: Pick a Wi-Fi network to connect to.
506      * <p>Input: Nothing.
507      * <p>Output: Nothing.
508      */
509     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
510     public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
511 
512     /**
513      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
514      * and will behave normally, i.e., it will attempt to automatically
515      * establish a connection to a remembered access point that is
516      * within range, and will do periodic scans if there are remembered
517      * access points but none are in range.
518      */
519     public static final int WIFI_MODE_FULL = 1;
520     /**
521      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
522      * but the only operation that will be supported is initiation of
523      * scans, and the subsequent reporting of scan results. No attempts
524      * will be made to automatically connect to remembered access points,
525      * nor will periodic scans be automatically performed looking for
526      * remembered access points. Scans must be explicitly requested by
527      * an application in this mode.
528      */
529     public static final int WIFI_MODE_SCAN_ONLY = 2;
530     /**
531      * In this Wi-Fi lock mode, Wi-Fi will be kept active as in mode
532      * {@link #WIFI_MODE_FULL} but it operates at high performance
533      * with minimum packet loss and low packet latency even when
534      * the device screen is off. This mode will consume more power
535      * and hence should be used only when there is a need for such
536      * an active connection.
537      * <p>
538      * An example use case is when a voice connection needs to be
539      * kept active even after the device screen goes off. Holding the
540      * regular {@link #WIFI_MODE_FULL} lock will keep the wifi
541      * connection active, but the connection can be lossy.
542      * Holding a {@link #WIFI_MODE_FULL_HIGH_PERF} lock for the
543      * duration of the voice call will improve the call quality.
544      * <p>
545      * When there is no support from the hardware, this lock mode
546      * will have the same behavior as {@link #WIFI_MODE_FULL}
547      */
548     public static final int WIFI_MODE_FULL_HIGH_PERF = 3;
549 
550     /** Anything worse than or equal to this will show 0 bars. */
551     private static final int MIN_RSSI = -100;
552 
553     /** Anything better than or equal to this will show the max bars. */
554     private static final int MAX_RSSI = -55;
555 
556     /**
557      * Number of RSSI levels used in the framework to initiate
558      * {@link #RSSI_CHANGED_ACTION} broadcast
559      * @hide
560      */
561     public static final int RSSI_LEVELS = 5;
562 
563     /**
564      * Auto settings in the driver. The driver could choose to operate on both
565      * 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band.
566      * @hide
567      */
568     public static final int WIFI_FREQUENCY_BAND_AUTO = 0;
569 
570     /**
571      * Operation on 5 GHz alone
572      * @hide
573      */
574     public static final int WIFI_FREQUENCY_BAND_5GHZ = 1;
575 
576     /**
577      * Operation on 2.4 GHz alone
578      * @hide
579      */
580     public static final int WIFI_FREQUENCY_BAND_2GHZ = 2;
581 
582     /** List of asyncronous notifications
583      * @hide
584      */
585     public static final int DATA_ACTIVITY_NOTIFICATION = 1;
586 
587     //Lowest bit indicates data reception and the second lowest
588     //bit indicates data transmitted
589     /** @hide */
590     public static final int DATA_ACTIVITY_NONE         = 0x00;
591     /** @hide */
592     public static final int DATA_ACTIVITY_IN           = 0x01;
593     /** @hide */
594     public static final int DATA_ACTIVITY_OUT          = 0x02;
595     /** @hide */
596     public static final int DATA_ACTIVITY_INOUT        = 0x03;
597 
598     /** @hide */
599     public static final boolean DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED = false;
600 
601     /* Maximum number of active locks we allow.
602      * This limit was added to prevent apps from creating a ridiculous number
603      * of locks and crashing the system by overflowing the global ref table.
604      */
605     private static final int MAX_ACTIVE_LOCKS = 50;
606 
607     /* Number of currently active WifiLocks and MulticastLocks */
608     private int mActiveLockCount;
609 
610     private Context mContext;
611     IWifiManager mService;
612     private final int mTargetSdkVersion;
613 
614     private static final int INVALID_KEY = 0;
615     private static int sListenerKey = 1;
616     private static final SparseArray sListenerMap = new SparseArray();
617     private static final Object sListenerMapLock = new Object();
618 
619     private static AsyncChannel sAsyncChannel;
620     private static CountDownLatch sConnected;
621     private static ConnectivityManager sCM;
622 
623     private static final Object sThreadRefLock = new Object();
624     private static int sThreadRefCount;
625     private static HandlerThread sHandlerThread;
626 
627     @GuardedBy("sCM")
628     // TODO: Introduce refcounting and make this a per-process static callback, instead of a
629     // per-WifiManager callback.
630     private PinningNetworkCallback mNetworkCallback;
631 
632     /**
633      * Create a new WifiManager instance.
634      * Applications will almost always want to use
635      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
636      * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
637      * @param context the application context
638      * @param service the Binder interface
639      * @hide - hide this because it takes in a parameter of type IWifiManager, which
640      * is a system private class.
641      */
WifiManager(Context context, IWifiManager service)642     public WifiManager(Context context, IWifiManager service) {
643         mContext = context;
644         mService = service;
645         mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
646         init();
647     }
648 
649     /**
650      * Return a list of all the networks configured in the supplicant.
651      * Not all fields of WifiConfiguration are returned. Only the following
652      * fields are filled in:
653      * <ul>
654      * <li>networkId</li>
655      * <li>SSID</li>
656      * <li>BSSID</li>
657      * <li>priority</li>
658      * <li>allowedProtocols</li>
659      * <li>allowedKeyManagement</li>
660      * <li>allowedAuthAlgorithms</li>
661      * <li>allowedPairwiseCiphers</li>
662      * <li>allowedGroupCiphers</li>
663      * </ul>
664      * @return a list of network configurations in the form of a list
665      * of {@link WifiConfiguration} objects. Upon failure to fetch or
666      * when when Wi-Fi is turned off, it can be null.
667      */
getConfiguredNetworks()668     public List<WifiConfiguration> getConfiguredNetworks() {
669         try {
670             return mService.getConfiguredNetworks();
671         } catch (RemoteException e) {
672             Log.w(TAG, "Caught RemoteException trying to get configured networks: " + e);
673             return null;
674         }
675     }
676 
677     /** @hide */
678     @SystemApi
getPrivilegedConfiguredNetworks()679     public List<WifiConfiguration> getPrivilegedConfiguredNetworks() {
680         try {
681             return mService.getPrivilegedConfiguredNetworks();
682         } catch (RemoteException e) {
683             return null;
684         }
685     }
686 
687     /** @hide */
688     @SystemApi
getConnectionStatistics()689     public WifiConnectionStatistics getConnectionStatistics() {
690         try {
691             return mService.getConnectionStatistics();
692         } catch (RemoteException e) {
693             return null;
694         }
695     }
696 
697     /**
698      * Returns a WifiConfiguration matching this ScanResult
699      * @param scanResult scanResult that represents the BSSID
700      * @return {@link WifiConfiguration} that matches this BSSID or null
701      * @hide
702      */
getMatchingWifiConfig(ScanResult scanResult)703     public WifiConfiguration getMatchingWifiConfig(ScanResult scanResult) {
704         try {
705             return mService.getMatchingWifiConfig(scanResult);
706         } catch (RemoteException e) {
707             return null;
708         }
709     }
710 
711     /**
712      * Add a new network description to the set of configured networks.
713      * The {@code networkId} field of the supplied configuration object
714      * is ignored.
715      * <p/>
716      * The new network will be marked DISABLED by default. To enable it,
717      * called {@link #enableNetwork}.
718      *
719      * @param config the set of variables that describe the configuration,
720      *            contained in a {@link WifiConfiguration} object.
721      * @return the ID of the newly created network description. This is used in
722      *         other operations to specified the network to be acted upon.
723      *         Returns {@code -1} on failure.
724      */
addNetwork(WifiConfiguration config)725     public int addNetwork(WifiConfiguration config) {
726         if (config == null) {
727             return -1;
728         }
729         config.networkId = -1;
730         return addOrUpdateNetwork(config);
731     }
732 
733     /**
734      * Update the network description of an existing configured network.
735      *
736      * @param config the set of variables that describe the configuration,
737      *            contained in a {@link WifiConfiguration} object. It may
738      *            be sparse, so that only the items that are being changed
739      *            are non-<code>null</code>. The {@code networkId} field
740      *            must be set to the ID of the existing network being updated.
741      * @return Returns the {@code networkId} of the supplied
742      *         {@code WifiConfiguration} on success.
743      *         <br/>
744      *         Returns {@code -1} on failure, including when the {@code networkId}
745      *         field of the {@code WifiConfiguration} does not refer to an
746      *         existing network.
747      */
updateNetwork(WifiConfiguration config)748     public int updateNetwork(WifiConfiguration config) {
749         if (config == null || config.networkId < 0) {
750             return -1;
751         }
752         return addOrUpdateNetwork(config);
753     }
754 
755     /**
756      * Internal method for doing the RPC that creates a new network description
757      * or updates an existing one.
758      *
759      * @param config The possibly sparse object containing the variables that
760      *         are to set or updated in the network description.
761      * @return the ID of the network on success, {@code -1} on failure.
762      */
addOrUpdateNetwork(WifiConfiguration config)763     private int addOrUpdateNetwork(WifiConfiguration config) {
764         try {
765             return mService.addOrUpdateNetwork(config);
766         } catch (RemoteException e) {
767             return -1;
768         }
769     }
770 
771     /**
772      * Remove the specified network from the list of configured networks.
773      * This may result in the asynchronous delivery of state change
774      * events.
775      * @param netId the integer that identifies the network configuration
776      * to the supplicant
777      * @return {@code true} if the operation succeeded
778      */
removeNetwork(int netId)779     public boolean removeNetwork(int netId) {
780         try {
781             return mService.removeNetwork(netId);
782         } catch (RemoteException e) {
783             return false;
784         }
785     }
786 
787     /**
788      * Allow a previously configured network to be associated with. If
789      * <code>disableOthers</code> is true, then all other configured
790      * networks are disabled, and an attempt to connect to the selected
791      * network is initiated. This may result in the asynchronous delivery
792      * of state change events.
793      * <p>
794      * <b>Note:</b> If an application's target SDK version is
795      * {@link android.os.Build.VERSION_CODES#LOLLIPOP} or newer, network
796      * communication may not use Wi-Fi even if Wi-Fi is connected; traffic may
797      * instead be sent through another network, such as cellular data,
798      * Bluetooth tethering, or Ethernet. For example, traffic will never use a
799      * Wi-Fi network that does not provide Internet access (e.g. a wireless
800      * printer), if another network that does offer Internet access (e.g.
801      * cellular data) is available. Applications that need to ensure that their
802      * network traffic uses Wi-Fi should use APIs such as
803      * {@link Network#bindSocket(java.net.Socket)},
804      * {@link Network#openConnection(java.net.URL)}, or
805      * {@link ConnectivityManager#bindProcessToNetwork} to do so.
806      *
807      * @param netId the ID of the network in the list of configured networks
808      * @param disableOthers if true, disable all other networks. The way to
809      * select a particular network to connect to is specify {@code true}
810      * for this parameter.
811      * @return {@code true} if the operation succeeded
812      */
enableNetwork(int netId, boolean disableOthers)813     public boolean enableNetwork(int netId, boolean disableOthers) {
814         final boolean pin = disableOthers && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
815         if (pin) {
816             registerPinningNetworkCallback();
817         }
818 
819         boolean success;
820         try {
821             success = mService.enableNetwork(netId, disableOthers);
822         } catch (RemoteException e) {
823             success = false;
824         }
825 
826         if (pin && !success) {
827             unregisterPinningNetworkCallback();
828         }
829 
830         return success;
831     }
832 
833     /**
834      * Disable a configured network. The specified network will not be
835      * a candidate for associating. This may result in the asynchronous
836      * delivery of state change events.
837      * @param netId the ID of the network as returned by {@link #addNetwork}.
838      * @return {@code true} if the operation succeeded
839      */
840     public boolean disableNetwork(int netId) {
841         try {
842             return mService.disableNetwork(netId);
843         } catch (RemoteException e) {
844             return false;
845         }
846     }
847 
848     /**
849      * Disassociate from the currently active access point. This may result
850      * in the asynchronous delivery of state change events.
851      * @return {@code true} if the operation succeeded
852      */
853     public boolean disconnect() {
854         try {
855             mService.disconnect();
856             return true;
857         } catch (RemoteException e) {
858             return false;
859         }
860     }
861 
862     /**
863      * Reconnect to the currently active access point, if we are currently
864      * disconnected. This may result in the asynchronous delivery of state
865      * change events.
866      * @return {@code true} if the operation succeeded
867      */
868     public boolean reconnect() {
869         try {
870             mService.reconnect();
871             return true;
872         } catch (RemoteException e) {
873             return false;
874         }
875     }
876 
877     /**
878      * Reconnect to the currently active access point, even if we are already
879      * connected. This may result in the asynchronous delivery of state
880      * change events.
881      * @return {@code true} if the operation succeeded
882      */
883     public boolean reassociate() {
884         try {
885             mService.reassociate();
886             return true;
887         } catch (RemoteException e) {
888             return false;
889         }
890     }
891 
892     /**
893      * Check that the supplicant daemon is responding to requests.
894      * @return {@code true} if we were able to communicate with the supplicant and
895      * it returned the expected response to the PING message.
896      */
897     public boolean pingSupplicant() {
898         if (mService == null)
899             return false;
900         try {
901             return mService.pingSupplicant();
902         } catch (RemoteException e) {
903             return false;
904         }
905     }
906 
907     /**
908      * Get a list of available channels for customized scan.
909      *
910      * @see {@link WifiChannel}
911      *
912      * @return the channel list, or null if not available
913      * @hide
914      */
915     public List<WifiChannel> getChannelList() {
916         try {
917             return mService.getChannelList();
918         } catch (RemoteException e) {
919             return null;
920         }
921     }
922 
923     /* Keep this list in sync with wifi_hal.h */
924     /** @hide */
925     public static final int WIFI_FEATURE_INFRA            = 0x0001;  // Basic infrastructure mode
926     /** @hide */
927     public static final int WIFI_FEATURE_INFRA_5G         = 0x0002;  // Support for 5 GHz Band
928     /** @hide */
929     public static final int WIFI_FEATURE_PASSPOINT        = 0x0004;  // Support for GAS/ANQP
930     /** @hide */
931     public static final int WIFI_FEATURE_P2P              = 0x0008;  // Wifi-Direct
932     /** @hide */
933     public static final int WIFI_FEATURE_MOBILE_HOTSPOT   = 0x0010;  // Soft AP
934     /** @hide */
935     public static final int WIFI_FEATURE_SCANNER          = 0x0020;  // WifiScanner APIs
936     /** @hide */
937     public static final int WIFI_FEATURE_NAN              = 0x0040;  // Neighbor Awareness Networking
938     /** @hide */
939     public static final int WIFI_FEATURE_D2D_RTT          = 0x0080;  // Device-to-device RTT
940     /** @hide */
941     public static final int WIFI_FEATURE_D2AP_RTT         = 0x0100;  // Device-to-AP RTT
942     /** @hide */
943     public static final int WIFI_FEATURE_BATCH_SCAN       = 0x0200;  // Batched Scan (deprecated)
944     /** @hide */
945     public static final int WIFI_FEATURE_PNO              = 0x0400;  // Preferred network offload
946     /** @hide */
947     public static final int WIFI_FEATURE_ADDITIONAL_STA   = 0x0800;  // Support for two STAs
948     /** @hide */
949     public static final int WIFI_FEATURE_TDLS             = 0x1000;  // Tunnel directed link setup
950     /** @hide */
951     public static final int WIFI_FEATURE_TDLS_OFFCHANNEL  = 0x2000;  // Support for TDLS off channel
952     /** @hide */
953     public static final int WIFI_FEATURE_EPR              = 0x4000;  // Enhanced power reporting
954     /** @hide */
955     public static final int WIFI_FEATURE_AP_STA            = 0x8000;  // Support for AP STA Concurrency
956     /** @hide */
957     public static final int WIFI_FEATURE_LINK_LAYER_STATS  = 0x10000; // Link layer stats collection
958     /** @hide */
959     public static final int WIFI_FEATURE_LOGGER            = 0x20000; // WiFi Logger
960     /** @hide */
961     public static final int WIFI_FEATURE_HAL_EPNO          = 0x40000; // WiFi PNO enhanced
962 
963     private int getSupportedFeatures() {
964         try {
965             return mService.getSupportedFeatures();
966         } catch (RemoteException e) {
967             return 0;
968         }
969     }
970 
971     private boolean isFeatureSupported(int feature) {
972         return (getSupportedFeatures() & feature) == feature;
973     }
974     /**
975      * @return true if this adapter supports 5 GHz band
976      */
977     public boolean is5GHzBandSupported() {
978         return isFeatureSupported(WIFI_FEATURE_INFRA_5G);
979     }
980 
981     /**
982      * @return true if this adapter supports passpoint
983      * @hide
984      */
985     public boolean isPasspointSupported() {
986         return isFeatureSupported(WIFI_FEATURE_PASSPOINT);
987     }
988 
989     /**
990      * @return true if this adapter supports WifiP2pManager (Wi-Fi Direct)
991      */
992     public boolean isP2pSupported() {
993         return isFeatureSupported(WIFI_FEATURE_P2P);
994     }
995 
996     /**
997      * @return true if this adapter supports portable Wi-Fi hotspot
998      * @hide
999      */
1000     @SystemApi
1001     public boolean isPortableHotspotSupported() {
1002         return isFeatureSupported(WIFI_FEATURE_MOBILE_HOTSPOT);
1003     }
1004 
1005     /**
1006      * @return true if this adapter supports WifiScanner APIs
1007      * @hide
1008      */
1009     @SystemApi
1010     public boolean isWifiScannerSupported() {
1011         return isFeatureSupported(WIFI_FEATURE_SCANNER);
1012     }
1013 
1014     /**
1015      * @return true if this adapter supports Neighbour Awareness Network APIs
1016      * @hide
1017      */
1018     public boolean isNanSupported() {
1019         return isFeatureSupported(WIFI_FEATURE_NAN);
1020     }
1021 
1022     /**
1023      * @return true if this adapter supports Device-to-device RTT
1024      * @hide
1025      */
1026     @SystemApi
1027     public boolean isDeviceToDeviceRttSupported() {
1028         return isFeatureSupported(WIFI_FEATURE_D2D_RTT);
1029     }
1030 
1031     /**
1032      * @return true if this adapter supports Device-to-AP RTT
1033      */
1034     @SystemApi
1035     public boolean isDeviceToApRttSupported() {
1036         return isFeatureSupported(WIFI_FEATURE_D2AP_RTT);
1037     }
1038 
1039     /**
1040      * @return true if this adapter supports offloaded connectivity scan
1041      */
1042     public boolean isPreferredNetworkOffloadSupported() {
1043         return isFeatureSupported(WIFI_FEATURE_PNO);
1044     }
1045 
1046     /**
1047      * @return true if this adapter supports multiple simultaneous connections
1048      * @hide
1049      */
1050     public boolean isAdditionalStaSupported() {
1051         return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA);
1052     }
1053 
1054     /**
1055      * @return true if this adapter supports Tunnel Directed Link Setup
1056      */
1057     public boolean isTdlsSupported() {
1058         return isFeatureSupported(WIFI_FEATURE_TDLS);
1059     }
1060 
1061     /**
1062      * @return true if this adapter supports Off Channel Tunnel Directed Link Setup
1063      * @hide
1064      */
1065     public boolean isOffChannelTdlsSupported() {
1066         return isFeatureSupported(WIFI_FEATURE_TDLS_OFFCHANNEL);
1067     }
1068 
1069     /**
1070      * @return true if this adapter supports advanced power/performance counters
1071      */
1072     public boolean isEnhancedPowerReportingSupported() {
1073         return isFeatureSupported(WIFI_FEATURE_LINK_LAYER_STATS);
1074     }
1075 
1076     /**
1077      * Return the record of {@link WifiActivityEnergyInfo} object that
1078      * has the activity and energy info. This can be used to ascertain what
1079      * the controller has been up to, since the last sample.
1080      * @param updateType Type of info, cached vs refreshed.
1081      *
1082      * @return a record with {@link WifiActivityEnergyInfo} or null if
1083      * report is unavailable or unsupported
1084      * @hide
1085      */
1086     public WifiActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) {
1087         if (mService == null) return null;
1088         try {
1089             WifiActivityEnergyInfo record;
1090             if (!isEnhancedPowerReportingSupported()) {
1091                 return null;
1092             }
1093             synchronized(this) {
1094                 record = mService.reportActivityInfo();
1095                 if (record != null && record.isValid()) {
1096                     return record;
1097                 } else {
1098                     return null;
1099                 }
1100             }
1101         } catch (RemoteException e) {
1102             Log.e(TAG, "getControllerActivityEnergyInfo: " + e);
1103         }
1104         return null;
1105     }
1106 
1107     /**
1108      * Request a scan for access points. Returns immediately. The availability
1109      * of the results is made known later by means of an asynchronous event sent
1110      * on completion of the scan.
1111      * @return {@code true} if the operation succeeded, i.e., the scan was initiated
1112      */
1113     public boolean startScan() {
1114         try {
1115             mService.startScan(null, null);
1116             return true;
1117         } catch (RemoteException e) {
1118             return false;
1119         }
1120     }
1121 
1122     /** @hide */
1123     @SystemApi
1124     public boolean startScan(WorkSource workSource) {
1125         try {
1126             mService.startScan(null, workSource);
1127             return true;
1128         } catch (RemoteException e) {
1129             return false;
1130         }
1131     }
1132 
1133     /**
1134      * startLocationRestrictedScan()
1135      * Trigger a scan which will not make use of DFS channels and is thus not suitable for
1136      * establishing wifi connection.
1137      * @hide
1138      */
1139     @SystemApi
1140     public boolean startLocationRestrictedScan(WorkSource workSource) {
1141         try {
1142             mService.startLocationRestrictedScan(workSource);
1143             return true;
1144         } catch (RemoteException e) {
1145             return false;
1146         }
1147     }
1148 
1149     /**
1150      * Request a scan for access points in specified channel list. Each channel is specified by its
1151      * frequency in MHz, e.g. "5500" (do NOT include "DFS" even though it is). The availability of
1152      * the results is made known later in the same way as {@link #startScan}.
1153      *
1154      * Note:
1155      *
1156      * 1. Customized scan is for non-connection purposes, i.e. it won't trigger a wifi connection
1157      *    even though it finds some known networks.
1158      *
1159      * 2. Customized scan result may include access points that is not specified in the channel
1160      *    list. An app will need to do frequency filtering if it wants to get pure results for the
1161      *    channel list it specified.
1162      *
1163      * @hide
1164      */
1165     public boolean startCustomizedScan(ScanSettings requested) {
1166         try {
1167             mService.startScan(requested, null);
1168             return true;
1169         } catch (RemoteException e) {
1170             return false;
1171         }
1172     }
1173 
1174     /** @hide */
1175     public boolean startCustomizedScan(ScanSettings requested, WorkSource workSource) {
1176         try {
1177             mService.startScan(requested, workSource);
1178             return true;
1179         } catch (RemoteException e) {
1180             return false;
1181         }
1182     }
1183 
1184     /**
1185      * Request a batched scan for access points.  To end your requested batched scan,
1186      * call stopBatchedScan with the same Settings.
1187      *
1188      * If there are mulitple requests for batched scans, the more demanding settings will
1189      * take precidence.
1190      *
1191      * @param requested {@link BatchedScanSettings} the scan settings requested.
1192      * @return false on known error
1193      * @hide
1194      */
1195     public boolean requestBatchedScan(BatchedScanSettings requested) {
1196         try {
1197             return mService.requestBatchedScan(requested, new Binder(), null);
1198         } catch (RemoteException e) { return false; }
1199     }
1200     /** @hide */
1201     public boolean requestBatchedScan(BatchedScanSettings requested, WorkSource workSource) {
1202         try {
1203             return mService.requestBatchedScan(requested, new Binder(), workSource);
1204         } catch (RemoteException e) { return false; }
1205     }
1206 
1207     /**
1208      * Check if the Batched Scan feature is supported.
1209      *
1210      * @return false if not supported.
1211      * @hide
1212      */
1213     @SystemApi
1214     public boolean isBatchedScanSupported() {
1215         try {
1216             return mService.isBatchedScanSupported();
1217         } catch (RemoteException e) { return false; }
1218     }
1219 
1220     /**
1221      * End a requested batch scan for this applicaiton.  Note that batched scan may
1222      * still occur if other apps are using them.
1223      *
1224      * @param requested {@link BatchedScanSettings} the scan settings you previously requested
1225      *        and now wish to stop.  A value of null here will stop all scans requested by the
1226      *        calling App.
1227      * @hide
1228      */
1229     public void stopBatchedScan(BatchedScanSettings requested) {
1230         try {
1231             mService.stopBatchedScan(requested);
1232         } catch (RemoteException e) {}
1233     }
1234 
1235     /**
1236      * Retrieve the latest batched scan result.  This should be called immediately after
1237      * {@link BATCHED_SCAN_RESULTS_AVAILABLE_ACTION} is received.
1238      * @hide
1239      */
1240     @SystemApi
1241     public List<BatchedScanResult> getBatchedScanResults() {
1242         try {
1243             return mService.getBatchedScanResults(mContext.getOpPackageName());
1244         } catch (RemoteException e) {
1245             return null;
1246         }
1247     }
1248 
1249     /**
1250      * Force a re-reading of batched scan results.  This will attempt
1251      * to read more information from the chip, but will do so at the expense
1252      * of previous data.  Rate limited to the current scan frequency.
1253      *
1254      * pollBatchedScan will always wait 1 period from the start of the batch
1255      * before trying to read from the chip, so if your #scans/batch == 1 this will
1256      * have no effect.
1257      *
1258      * If you had already waited 1 period before calling, this should have
1259      * immediate (though async) effect.
1260      *
1261      * If you call before that 1 period is up this will set up a timer and fetch
1262      * results when the 1 period is up.
1263      *
1264      * Servicing a pollBatchedScan request (immediate or after timed delay) starts a
1265      * new batch, so if you were doing 10 scans/batch and called in the 4th scan, you
1266      * would get data in the 4th and then again 10 scans later.
1267      * @hide
1268      */
1269     public void pollBatchedScan() {
1270         try {
1271             mService.pollBatchedScan();
1272         } catch (RemoteException e) { }
1273     }
1274 
1275     /**
1276      * Creates a configuration token describing the network referenced by {@code netId}
1277      * of MIME type application/vnd.wfa.wsc. Can be used to configure WiFi networks via NFC.
1278      *
1279      * @return hex-string encoded configuration token
1280      * @hide
1281      */
1282     public String getWpsNfcConfigurationToken(int netId) {
1283         try {
1284             return mService.getWpsNfcConfigurationToken(netId);
1285         } catch (RemoteException e) {
1286             return null;
1287         }
1288     }
1289 
1290     /**
1291      * Return dynamic information about the current Wi-Fi connection, if any is active.
1292      * @return the Wi-Fi information, contained in {@link WifiInfo}.
1293      */
1294     public WifiInfo getConnectionInfo() {
1295         try {
1296             return mService.getConnectionInfo();
1297         } catch (RemoteException e) {
1298             return null;
1299         }
1300     }
1301 
1302     /**
1303      * Return the results of the latest access point scan.
1304      * @return the list of access points found in the most recent scan. An app must hold
1305      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
1306      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
1307      * in order to get valid results.
1308      */
1309     public List<ScanResult> getScanResults() {
1310         try {
1311             return mService.getScanResults(mContext.getOpPackageName());
1312         } catch (RemoteException e) {
1313             return null;
1314         }
1315     }
1316 
1317     /**
1318      * Check if scanning is always available.
1319      *
1320      * If this return {@code true}, apps can issue {@link #startScan} and fetch scan results
1321      * even when Wi-Fi is turned off.
1322      *
1323      * To change this setting, see {@link #ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE}.
1324      */
1325     public boolean isScanAlwaysAvailable() {
1326         try {
1327             return mService.isScanAlwaysAvailable();
1328         } catch (RemoteException e) {
1329             return false;
1330         }
1331     }
1332 
1333     /**
1334      * Tell the supplicant to persist the current list of configured networks.
1335      * <p>
1336      * Note: It is possible for this method to change the network IDs of
1337      * existing networks. You should assume the network IDs can be different
1338      * after calling this method.
1339      *
1340      * @return {@code true} if the operation succeeded
1341      */
1342     public boolean saveConfiguration() {
1343         try {
1344             return mService.saveConfiguration();
1345         } catch (RemoteException e) {
1346             return false;
1347         }
1348     }
1349 
1350     /**
1351      * Set the country code.
1352      * @param countryCode country code in ISO 3166 format.
1353      * @param persist {@code true} if this needs to be remembered
1354      *
1355      * @hide
1356      */
1357     public void setCountryCode(String country, boolean persist) {
1358         try {
1359             mService.setCountryCode(country, persist);
1360         } catch (RemoteException e) { }
1361     }
1362 
1363     /**
1364     * get the country code.
1365     * @return the country code in ISO 3166 format.
1366     *
1367     * @hide
1368     */
1369     public String getCountryCode() {
1370        try {
1371            String country = mService.getCountryCode();
1372            return(country);
1373        } catch (RemoteException e) {
1374            return null;
1375        }
1376     }
1377 
1378     /**
1379      * Set the operational frequency band.
1380      * @param band  One of
1381      *     {@link #WIFI_FREQUENCY_BAND_AUTO},
1382      *     {@link #WIFI_FREQUENCY_BAND_5GHZ},
1383      *     {@link #WIFI_FREQUENCY_BAND_2GHZ},
1384      * @param persist {@code true} if this needs to be remembered
1385      * @hide
1386      */
1387     public void setFrequencyBand(int band, boolean persist) {
1388         try {
1389             mService.setFrequencyBand(band, persist);
1390         } catch (RemoteException e) { }
1391     }
1392 
1393     /**
1394      * Get the operational frequency band.
1395      * @return One of
1396      *     {@link #WIFI_FREQUENCY_BAND_AUTO},
1397      *     {@link #WIFI_FREQUENCY_BAND_5GHZ},
1398      *     {@link #WIFI_FREQUENCY_BAND_2GHZ} or
1399      *     {@code -1} on failure.
1400      * @hide
1401      */
1402     public int getFrequencyBand() {
1403         try {
1404             return mService.getFrequencyBand();
1405         } catch (RemoteException e) {
1406             return -1;
1407         }
1408     }
1409 
1410     /**
1411      * Check if the chipset supports dual frequency band (2.4 GHz and 5 GHz)
1412      * @return {@code true} if supported, {@code false} otherwise.
1413      * @hide
1414      */
1415     public boolean isDualBandSupported() {
1416         try {
1417             return mService.isDualBandSupported();
1418         } catch (RemoteException e) {
1419             return false;
1420         }
1421     }
1422 
1423     /**
1424      * Return the DHCP-assigned addresses from the last successful DHCP request,
1425      * if any.
1426      * @return the DHCP information
1427      */
1428     public DhcpInfo getDhcpInfo() {
1429         try {
1430             return mService.getDhcpInfo();
1431         } catch (RemoteException e) {
1432             return null;
1433         }
1434     }
1435 
1436     /**
1437      * Enable or disable Wi-Fi.
1438      * @param enabled {@code true} to enable, {@code false} to disable.
1439      * @return {@code true} if the operation succeeds (or if the existing state
1440      *         is the same as the requested state).
1441      */
1442     public boolean setWifiEnabled(boolean enabled) {
1443         try {
1444             return mService.setWifiEnabled(enabled);
1445         } catch (RemoteException e) {
1446             return false;
1447         }
1448     }
1449 
1450     /**
1451      * Gets the Wi-Fi enabled state.
1452      * @return One of {@link #WIFI_STATE_DISABLED},
1453      *         {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED},
1454      *         {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN}
1455      * @see #isWifiEnabled()
1456      */
1457     public int getWifiState() {
1458         try {
1459             return mService.getWifiEnabledState();
1460         } catch (RemoteException e) {
1461             return WIFI_STATE_UNKNOWN;
1462         }
1463     }
1464 
1465     /**
1466      * Return whether Wi-Fi is enabled or disabled.
1467      * @return {@code true} if Wi-Fi is enabled
1468      * @see #getWifiState()
1469      */
1470     public boolean isWifiEnabled() {
1471         return getWifiState() == WIFI_STATE_ENABLED;
1472     }
1473 
1474     /**
1475      * Return TX packet counter, for CTS test of WiFi watchdog.
1476      * @param listener is the interface to receive result
1477      *
1478      * @hide for CTS test only
1479      */
1480     public void getTxPacketCount(TxPacketCountListener listener) {
1481         validateChannel();
1482         sAsyncChannel.sendMessage(RSSI_PKTCNT_FETCH, 0, putListener(listener));
1483     }
1484 
1485     /**
1486      * Calculates the level of the signal. This should be used any time a signal
1487      * is being shown.
1488      *
1489      * @param rssi The power of the signal measured in RSSI.
1490      * @param numLevels The number of levels to consider in the calculated
1491      *            level.
1492      * @return A level of the signal, given in the range of 0 to numLevels-1
1493      *         (both inclusive).
1494      */
1495     public static int calculateSignalLevel(int rssi, int numLevels) {
1496         if (rssi <= MIN_RSSI) {
1497             return 0;
1498         } else if (rssi >= MAX_RSSI) {
1499             return numLevels - 1;
1500         } else {
1501             float inputRange = (MAX_RSSI - MIN_RSSI);
1502             float outputRange = (numLevels - 1);
1503             return (int)((float)(rssi - MIN_RSSI) * outputRange / inputRange);
1504         }
1505     }
1506 
1507     /**
1508      * Compares two signal strengths.
1509      *
1510      * @param rssiA The power of the first signal measured in RSSI.
1511      * @param rssiB The power of the second signal measured in RSSI.
1512      * @return Returns <0 if the first signal is weaker than the second signal,
1513      *         0 if the two signals have the same strength, and >0 if the first
1514      *         signal is stronger than the second signal.
1515      */
1516     public static int compareSignalLevel(int rssiA, int rssiB) {
1517         return rssiA - rssiB;
1518     }
1519 
1520     /**
1521      * Start AccessPoint mode with the specified
1522      * configuration. If the radio is already running in
1523      * AP mode, update the new configuration
1524      * Note that starting in access point mode disables station
1525      * mode operation
1526      * @param wifiConfig SSID, security and channel details as
1527      *        part of WifiConfiguration
1528      * @return {@code true} if the operation succeeds, {@code false} otherwise
1529      *
1530      * @hide Dont open up yet
1531      */
1532     public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
1533         try {
1534             mService.setWifiApEnabled(wifiConfig, enabled);
1535             return true;
1536         } catch (RemoteException e) {
1537             return false;
1538         }
1539     }
1540 
1541     /**
1542      * Gets the Wi-Fi enabled state.
1543      * @return One of {@link #WIFI_AP_STATE_DISABLED},
1544      *         {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
1545      *         {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
1546      * @see #isWifiApEnabled()
1547      *
1548      * @hide Dont open yet
1549      */
1550     public int getWifiApState() {
1551         try {
1552             return mService.getWifiApEnabledState();
1553         } catch (RemoteException e) {
1554             return WIFI_AP_STATE_FAILED;
1555         }
1556     }
1557 
1558     /**
1559      * Return whether Wi-Fi AP is enabled or disabled.
1560      * @return {@code true} if Wi-Fi AP is enabled
1561      * @see #getWifiApState()
1562      *
1563      * @hide Dont open yet
1564      */
1565     public boolean isWifiApEnabled() {
1566         return getWifiApState() == WIFI_AP_STATE_ENABLED;
1567     }
1568 
1569     /**
1570      * Gets the Wi-Fi AP Configuration.
1571      * @return AP details in WifiConfiguration
1572      *
1573      * @hide Dont open yet
1574      */
1575     public WifiConfiguration getWifiApConfiguration() {
1576         try {
1577             return mService.getWifiApConfiguration();
1578         } catch (RemoteException e) {
1579             return null;
1580         }
1581     }
1582 
1583     /**
1584      * Builds a WifiConfiguration from Hotspot 2.0 MIME file.
1585      * @return AP details in WifiConfiguration
1586      *
1587      * @hide Dont open yet
1588      */
1589     public WifiConfiguration buildWifiConfig(String uriString, String mimeType, byte[] data) {
1590         try {
1591             return mService.buildWifiConfig(uriString, mimeType, data);
1592         } catch (RemoteException e) {
1593             Log.w(TAG, "Caught RemoteException trying to build wifi config: " + e);
1594             return null;
1595         }
1596     }
1597 
1598     /**
1599      * Sets the Wi-Fi AP Configuration.
1600      * @return {@code true} if the operation succeeded, {@code false} otherwise
1601      *
1602      * @hide Dont open yet
1603      */
1604     public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
1605         try {
1606             mService.setWifiApConfiguration(wifiConfig);
1607             return true;
1608         } catch (RemoteException e) {
1609             return false;
1610         }
1611     }
1612 
1613    /**
1614      * Start the driver and connect to network.
1615      *
1616      * This function will over-ride WifiLock and device idle status. For example,
1617      * even if the device is idle or there is only a scan-only lock held,
1618      * a start wifi would mean that wifi connection is kept active until
1619      * a stopWifi() is sent.
1620      *
1621      * This API is used by WifiStateTracker
1622      *
1623      * @return {@code true} if the operation succeeds else {@code false}
1624      * @hide
1625      */
1626     public boolean startWifi() {
1627         try {
1628             mService.startWifi();
1629             return true;
1630         } catch (RemoteException e) {
1631             return false;
1632         }
1633     }
1634 
1635     /**
1636      * Disconnect from a network (if any) and stop the driver.
1637      *
1638      * This function will over-ride WifiLock and device idle status. Wi-Fi
1639      * stays inactive until a startWifi() is issued.
1640      *
1641      * This API is used by WifiStateTracker
1642      *
1643      * @return {@code true} if the operation succeeds else {@code false}
1644      * @hide
1645      */
1646     public boolean stopWifi() {
1647         try {
1648             mService.stopWifi();
1649             return true;
1650         } catch (RemoteException e) {
1651             return false;
1652         }
1653     }
1654 
1655     /**
1656      * Add a bssid to the supplicant blacklist
1657      *
1658      * This API is used by WifiWatchdogService
1659      *
1660      * @return {@code true} if the operation succeeds else {@code false}
1661      * @hide
1662      */
1663     public boolean addToBlacklist(String bssid) {
1664         try {
1665             mService.addToBlacklist(bssid);
1666             return true;
1667         } catch (RemoteException e) {
1668             return false;
1669         }
1670     }
1671 
1672     /**
1673      * Clear the supplicant blacklist
1674      *
1675      * This API is used by WifiWatchdogService
1676      *
1677      * @return {@code true} if the operation succeeds else {@code false}
1678      * @hide
1679      */
1680     public boolean clearBlacklist() {
1681         try {
1682             mService.clearBlacklist();
1683             return true;
1684         } catch (RemoteException e) {
1685             return false;
1686         }
1687     }
1688 
1689 
1690     /**
1691      * Enable/Disable TDLS on a specific local route.
1692      *
1693      * <p>
1694      * TDLS enables two wireless endpoints to talk to each other directly
1695      * without going through the access point that is managing the local
1696      * network. It saves bandwidth and improves quality of the link.
1697      * </p>
1698      * <p>
1699      * This API enables/disables the option of using TDLS. If enabled, the
1700      * underlying hardware is free to use TDLS or a hop through the access
1701      * point. If disabled, existing TDLS session is torn down and
1702      * hardware is restricted to use access point for transferring wireless
1703      * packets. Default value for all routes is 'disabled', meaning restricted
1704      * to use access point for transferring packets.
1705      * </p>
1706      *
1707      * @param remoteIPAddress IP address of the endpoint to setup TDLS with
1708      * @param enable true = setup and false = tear down TDLS
1709      */
1710     public void setTdlsEnabled(InetAddress remoteIPAddress, boolean enable) {
1711         try {
1712             mService.enableTdls(remoteIPAddress.getHostAddress(), enable);
1713         } catch (RemoteException e) {
1714             // Just ignore the exception
1715         }
1716     }
1717 
1718     /**
1719      * Similar to {@link #setTdlsEnabled(InetAddress, boolean) }, except
1720      * this version allows you to specify remote endpoint with a MAC address.
1721      * @param remoteMacAddress MAC address of the remote endpoint such as 00:00:0c:9f:f2:ab
1722      * @param enable true = setup and false = tear down TDLS
1723      */
1724     public void setTdlsEnabledWithMacAddress(String remoteMacAddress, boolean enable) {
1725         try {
1726             mService.enableTdlsWithMacAddress(remoteMacAddress, enable);
1727         } catch (RemoteException e) {
1728             // Just ignore the exception
1729         }
1730     }
1731 
1732     /* TODO: deprecate synchronous API and open up the following API */
1733 
1734     private static final int BASE = Protocol.BASE_WIFI_MANAGER;
1735 
1736     /* Commands to WifiService */
1737     /** @hide */
1738     public static final int CONNECT_NETWORK                 = BASE + 1;
1739     /** @hide */
1740     public static final int CONNECT_NETWORK_FAILED          = BASE + 2;
1741     /** @hide */
1742     public static final int CONNECT_NETWORK_SUCCEEDED       = BASE + 3;
1743 
1744     /** @hide */
1745     public static final int FORGET_NETWORK                  = BASE + 4;
1746     /** @hide */
1747     public static final int FORGET_NETWORK_FAILED           = BASE + 5;
1748     /** @hide */
1749     public static final int FORGET_NETWORK_SUCCEEDED        = BASE + 6;
1750 
1751     /** @hide */
1752     public static final int SAVE_NETWORK                    = BASE + 7;
1753     /** @hide */
1754     public static final int SAVE_NETWORK_FAILED             = BASE + 8;
1755     /** @hide */
1756     public static final int SAVE_NETWORK_SUCCEEDED          = BASE + 9;
1757 
1758     /** @hide */
1759     public static final int START_WPS                       = BASE + 10;
1760     /** @hide */
1761     public static final int START_WPS_SUCCEEDED             = BASE + 11;
1762     /** @hide */
1763     public static final int WPS_FAILED                      = BASE + 12;
1764     /** @hide */
1765     public static final int WPS_COMPLETED                   = BASE + 13;
1766 
1767     /** @hide */
1768     public static final int CANCEL_WPS                      = BASE + 14;
1769     /** @hide */
1770     public static final int CANCEL_WPS_FAILED               = BASE + 15;
1771     /** @hide */
1772     public static final int CANCEL_WPS_SUCCEDED             = BASE + 16;
1773 
1774     /** @hide */
1775     public static final int DISABLE_NETWORK                 = BASE + 17;
1776     /** @hide */
1777     public static final int DISABLE_NETWORK_FAILED          = BASE + 18;
1778     /** @hide */
1779     public static final int DISABLE_NETWORK_SUCCEEDED       = BASE + 19;
1780 
1781     /** @hide */
1782     public static final int RSSI_PKTCNT_FETCH               = BASE + 20;
1783     /** @hide */
1784     public static final int RSSI_PKTCNT_FETCH_SUCCEEDED     = BASE + 21;
1785     /** @hide */
1786     public static final int RSSI_PKTCNT_FETCH_FAILED        = BASE + 22;
1787 
1788     /**
1789      * Passed with {@link ActionListener#onFailure}.
1790      * Indicates that the operation failed due to an internal error.
1791      * @hide
1792      */
1793     public static final int ERROR                       = 0;
1794 
1795     /**
1796      * Passed with {@link ActionListener#onFailure}.
1797      * Indicates that the operation is already in progress
1798      * @hide
1799      */
1800     public static final int IN_PROGRESS                 = 1;
1801 
1802     /**
1803      * Passed with {@link ActionListener#onFailure}.
1804      * Indicates that the operation failed because the framework is busy and
1805      * unable to service the request
1806      * @hide
1807      */
1808     public static final int BUSY                        = 2;
1809 
1810     /* WPS specific errors */
1811     /** WPS overlap detected */
1812     public static final int WPS_OVERLAP_ERROR           = 3;
1813     /** WEP on WPS is prohibited */
1814     public static final int WPS_WEP_PROHIBITED          = 4;
1815     /** TKIP only prohibited */
1816     public static final int WPS_TKIP_ONLY_PROHIBITED    = 5;
1817     /** Authentication failure on WPS */
1818     public static final int WPS_AUTH_FAILURE            = 6;
1819     /** WPS timed out */
1820     public static final int WPS_TIMED_OUT               = 7;
1821 
1822     /**
1823      * Passed with {@link ActionListener#onFailure}.
1824      * Indicates that the operation failed due to invalid inputs
1825      * @hide
1826      */
1827     public static final int INVALID_ARGS                = 8;
1828 
1829     /**
1830      * Passed with {@link ActionListener#onFailure}.
1831      * Indicates that the operation failed due to user permissions.
1832      * @hide
1833      */
1834     public static final int NOT_AUTHORIZED              = 9;
1835 
1836     /**
1837      * Interface for callback invocation on an application action
1838      * @hide
1839      */
1840     public interface ActionListener {
1841         /** The operation succeeded */
1842         public void onSuccess();
1843         /**
1844          * The operation failed
1845          * @param reason The reason for failure could be one of
1846          * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY}
1847          */
1848         public void onFailure(int reason);
1849     }
1850 
1851     /** Interface for callback invocation on a start WPS action */
1852     public static abstract class WpsCallback {
1853         /** WPS start succeeded */
1854         public abstract void onStarted(String pin);
1855 
1856         /** WPS operation completed succesfully */
1857         public abstract void onSucceeded();
1858 
1859         /**
1860          * WPS operation failed
1861          * @param reason The reason for failure could be one of
1862          * {@link #WPS_TKIP_ONLY_PROHIBITED}, {@link #WPS_OVERLAP_ERROR},
1863          * {@link #WPS_WEP_PROHIBITED}, {@link #WPS_TIMED_OUT} or {@link #WPS_AUTH_FAILURE}
1864          * and some generic errors.
1865          */
1866         public abstract void onFailed(int reason);
1867     }
1868 
1869     /** Interface for callback invocation on a TX packet count poll action {@hide} */
1870     public interface TxPacketCountListener {
1871         /**
1872          * The operation succeeded
1873          * @param count TX packet counter
1874          */
1875         public void onSuccess(int count);
1876         /**
1877          * The operation failed
1878          * @param reason The reason for failure could be one of
1879          * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY}
1880          */
1881         public void onFailure(int reason);
1882     }
1883 
1884     private static class ServiceHandler extends Handler {
1885         ServiceHandler(Looper looper) {
1886             super(looper);
1887         }
1888 
1889         @Override
1890         public void handleMessage(Message message) {
1891             Object listener = removeListener(message.arg2);
1892             switch (message.what) {
1893                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
1894                     if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
1895                         sAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
1896                     } else {
1897                         Log.e(TAG, "Failed to set up channel connection");
1898                         // This will cause all further async API calls on the WifiManager
1899                         // to fail and throw an exception
1900                         sAsyncChannel = null;
1901                     }
1902                     sConnected.countDown();
1903                     break;
1904                 case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
1905                     // Ignore
1906                     break;
1907                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
1908                     Log.e(TAG, "Channel connection lost");
1909                     // This will cause all further async API calls on the WifiManager
1910                     // to fail and throw an exception
1911                     sAsyncChannel = null;
1912                     getLooper().quit();
1913                     break;
1914                     /* ActionListeners grouped together */
1915                 case WifiManager.CONNECT_NETWORK_FAILED:
1916                 case WifiManager.FORGET_NETWORK_FAILED:
1917                 case WifiManager.SAVE_NETWORK_FAILED:
1918                 case WifiManager.DISABLE_NETWORK_FAILED:
1919                     if (listener != null) {
1920                         ((ActionListener) listener).onFailure(message.arg1);
1921                     }
1922                     break;
1923                     /* ActionListeners grouped together */
1924                 case WifiManager.CONNECT_NETWORK_SUCCEEDED:
1925                 case WifiManager.FORGET_NETWORK_SUCCEEDED:
1926                 case WifiManager.SAVE_NETWORK_SUCCEEDED:
1927                 case WifiManager.DISABLE_NETWORK_SUCCEEDED:
1928                     if (listener != null) {
1929                         ((ActionListener) listener).onSuccess();
1930                     }
1931                     break;
1932                 case WifiManager.START_WPS_SUCCEEDED:
1933                     if (listener != null) {
1934                         WpsResult result = (WpsResult) message.obj;
1935                         ((WpsCallback) listener).onStarted(result.pin);
1936                         //Listener needs to stay until completion or failure
1937                         synchronized(sListenerMapLock) {
1938                             sListenerMap.put(message.arg2, listener);
1939                         }
1940                     }
1941                     break;
1942                 case WifiManager.WPS_COMPLETED:
1943                     if (listener != null) {
1944                         ((WpsCallback) listener).onSucceeded();
1945                     }
1946                     break;
1947                 case WifiManager.WPS_FAILED:
1948                     if (listener != null) {
1949                         ((WpsCallback) listener).onFailed(message.arg1);
1950                     }
1951                     break;
1952                 case WifiManager.CANCEL_WPS_SUCCEDED:
1953                     if (listener != null) {
1954                         ((WpsCallback) listener).onSucceeded();
1955                     }
1956                     break;
1957                 case WifiManager.CANCEL_WPS_FAILED:
1958                     if (listener != null) {
1959                         ((WpsCallback) listener).onFailed(message.arg1);
1960                     }
1961                     break;
1962                 case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED:
1963                     if (listener != null) {
1964                         RssiPacketCountInfo info = (RssiPacketCountInfo) message.obj;
1965                         if (info != null)
1966                             ((TxPacketCountListener) listener).onSuccess(info.txgood + info.txbad);
1967                         else
1968                             ((TxPacketCountListener) listener).onFailure(ERROR);
1969                     }
1970                     break;
1971                 case WifiManager.RSSI_PKTCNT_FETCH_FAILED:
1972                     if (listener != null) {
1973                         ((TxPacketCountListener) listener).onFailure(message.arg1);
1974                     }
1975                     break;
1976                 default:
1977                     //ignore
1978                     break;
1979             }
1980         }
1981     }
1982 
1983     private static int putListener(Object listener) {
1984         if (listener == null) return INVALID_KEY;
1985         int key;
1986         synchronized (sListenerMapLock) {
1987             do {
1988                 key = sListenerKey++;
1989             } while (key == INVALID_KEY);
1990             sListenerMap.put(key, listener);
1991         }
1992         return key;
1993     }
1994 
1995     private static Object removeListener(int key) {
1996         if (key == INVALID_KEY) return null;
1997         synchronized (sListenerMapLock) {
1998             Object listener = sListenerMap.get(key);
1999             sListenerMap.remove(key);
2000             return listener;
2001         }
2002     }
2003 
2004     private void init() {
2005         synchronized (sThreadRefLock) {
2006             if (++sThreadRefCount == 1) {
2007                 Messenger messenger = getWifiServiceMessenger();
2008                 if (messenger == null) {
2009                     sAsyncChannel = null;
2010                     return;
2011                 }
2012 
2013                 sHandlerThread = new HandlerThread("WifiManager");
2014                 sAsyncChannel = new AsyncChannel();
2015                 sConnected = new CountDownLatch(1);
2016 
2017                 sHandlerThread.start();
2018                 Handler handler = new ServiceHandler(sHandlerThread.getLooper());
2019                 sAsyncChannel.connect(mContext, handler, messenger);
2020                 try {
2021                     sConnected.await();
2022                 } catch (InterruptedException e) {
2023                     Log.e(TAG, "interrupted wait at init");
2024                 }
2025             }
2026         }
2027     }
2028 
2029     private void validateChannel() {
2030         if (sAsyncChannel == null) throw new IllegalStateException(
2031                 "No permission to access and change wifi or a bad initialization");
2032     }
2033 
2034     private void initConnectivityManager() {
2035         // TODO: what happens if an app calls a WifiManager API before ConnectivityManager is
2036         // registered? Can we fix this by starting ConnectivityService before WifiService?
2037         if (sCM == null) {
2038             sCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
2039             if (sCM == null) {
2040                 throw new IllegalStateException("Bad luck, ConnectivityService not started.");
2041             }
2042         }
2043     }
2044 
2045     /**
2046      * A NetworkCallback that pins the process to the first wifi network to connect.
2047      *
2048      * We use this to maintain compatibility with pre-M apps that call WifiManager.enableNetwork()
2049      * to connect to a Wi-Fi network that has no Internet access, and then assume that they will be
2050      * able to use that network because it's the system default.
2051      *
2052      * In order to maintain compatibility with apps that call setProcessDefaultNetwork themselves,
2053      * we try not to set the default network unless they have already done so, and we try not to
2054      * clear the default network unless we set it ourselves.
2055      *
2056      * This should maintain behaviour that's compatible with L, which would pin the whole system to
2057      * any wifi network that was created via enableNetwork(..., true) until that network
2058      * disconnected.
2059      *
2060      * Note that while this hack allows network traffic to flow, it is quite limited. For example:
2061      *
2062      * 1. setProcessDefaultNetwork only affects this process, so:
2063      *    - Any subprocesses spawned by this process will not be pinned to Wi-Fi.
2064      *    - If this app relies on any other apps on the device also being on Wi-Fi, that won't work
2065      *      either, because other apps on the device will not be pinned.
2066      * 2. The behaviour of other APIs is not modified. For example:
2067      *    - getActiveNetworkInfo will return the system default network, not Wi-Fi.
2068      *    - There will be no CONNECTIVITY_ACTION broadcasts about TYPE_WIFI.
2069      *    - getProcessDefaultNetwork will not return null, so if any apps are relying on that, they
2070      *      will be surprised as well.
2071      */
2072     private class PinningNetworkCallback extends NetworkCallback {
2073         private Network mPinnedNetwork;
2074 
2075         @Override
2076         public void onPreCheck(Network network) {
2077             if (sCM.getProcessDefaultNetwork() == null && mPinnedNetwork == null) {
2078                 sCM.setProcessDefaultNetwork(network);
2079                 mPinnedNetwork = network;
2080                 Log.d(TAG, "Wifi alternate reality enabled on network " + network);
2081             }
2082         }
2083 
2084         @Override
2085         public void onLost(Network network) {
2086             if (network.equals(mPinnedNetwork) && network.equals(sCM.getProcessDefaultNetwork())) {
2087                 sCM.setProcessDefaultNetwork(null);
2088                 Log.d(TAG, "Wifi alternate reality disabled on network " + network);
2089                 mPinnedNetwork = null;
2090                 unregisterPinningNetworkCallback();
2091             }
2092         }
2093     }
2094 
2095     private void registerPinningNetworkCallback() {
2096         initConnectivityManager();
2097         synchronized (sCM) {
2098             if (mNetworkCallback == null) {
2099                 // TODO: clear all capabilities.
2100                 NetworkRequest request = new NetworkRequest.Builder()
2101                         .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
2102                         .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
2103                         .build();
2104                 mNetworkCallback = new PinningNetworkCallback();
2105                 try {
2106                     sCM.registerNetworkCallback(request, mNetworkCallback);
2107                 } catch (SecurityException e) {
2108                     Log.d(TAG, "Failed to register network callback", e);
2109                 }
2110             }
2111         }
2112     }
2113 
2114     private void unregisterPinningNetworkCallback() {
2115         initConnectivityManager();
2116         synchronized (sCM) {
2117             if (mNetworkCallback != null) {
2118                 try {
2119                     sCM.unregisterNetworkCallback(mNetworkCallback);
2120                 } catch (SecurityException e) {
2121                     Log.d(TAG, "Failed to unregister network callback", e);
2122                 }
2123                 mNetworkCallback = null;
2124             }
2125         }
2126     }
2127 
2128     /**
2129      * Connect to a network with the given configuration. The network also
2130      * gets added to the supplicant configuration.
2131      *
2132      * For a new network, this function is used instead of a
2133      * sequence of addNetwork(), enableNetwork(), saveConfiguration() and
2134      * reconnect()
2135      *
2136      * @param config the set of variables that describe the configuration,
2137      *            contained in a {@link WifiConfiguration} object.
2138      * @param listener for callbacks on success or failure. Can be null.
2139      * @throws IllegalStateException if the WifiManager instance needs to be
2140      * initialized again
2141      *
2142      * @hide
2143      */
2144     public void connect(WifiConfiguration config, ActionListener listener) {
2145         if (config == null) throw new IllegalArgumentException("config cannot be null");
2146         validateChannel();
2147         // Use INVALID_NETWORK_ID for arg1 when passing a config object
2148         // arg1 is used to pass network id when the network already exists
2149         sAsyncChannel.sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,
2150                 putListener(listener), config);
2151     }
2152 
2153     /**
2154      * Connect to a network with the given networkId.
2155      *
2156      * This function is used instead of a enableNetwork(), saveConfiguration() and
2157      * reconnect()
2158      *
2159      * @param networkId the network id identifiying the network in the
2160      *                supplicant configuration list
2161      * @param listener for callbacks on success or failure. Can be null.
2162      * @throws IllegalStateException if the WifiManager instance needs to be
2163      * initialized again
2164      * @hide
2165      */
2166     public void connect(int networkId, ActionListener listener) {
2167         if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
2168         validateChannel();
2169         sAsyncChannel.sendMessage(CONNECT_NETWORK, networkId, putListener(listener));
2170     }
2171 
2172     /**
2173      * Save the given network in the supplicant config. If the network already
2174      * exists, the configuration is updated. A new network is enabled
2175      * by default.
2176      *
2177      * For a new network, this function is used instead of a
2178      * sequence of addNetwork(), enableNetwork() and saveConfiguration().
2179      *
2180      * For an existing network, it accomplishes the task of updateNetwork()
2181      * and saveConfiguration()
2182      *
2183      * @param config the set of variables that describe the configuration,
2184      *            contained in a {@link WifiConfiguration} object.
2185      * @param listener for callbacks on success or failure. Can be null.
2186      * @throws IllegalStateException if the WifiManager instance needs to be
2187      * initialized again
2188      * @hide
2189      */
2190     public void save(WifiConfiguration config, ActionListener listener) {
2191         if (config == null) throw new IllegalArgumentException("config cannot be null");
2192         validateChannel();
2193         sAsyncChannel.sendMessage(SAVE_NETWORK, 0, putListener(listener), config);
2194     }
2195 
2196     /**
2197      * Delete the network in the supplicant config.
2198      *
2199      * This function is used instead of a sequence of removeNetwork()
2200      * and saveConfiguration().
2201      *
2202      * @param config the set of variables that describe the configuration,
2203      *            contained in a {@link WifiConfiguration} object.
2204      * @param listener for callbacks on success or failure. Can be null.
2205      * @throws IllegalStateException if the WifiManager instance needs to be
2206      * initialized again
2207      * @hide
2208      */
2209     public void forget(int netId, ActionListener listener) {
2210         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
2211         validateChannel();
2212         sAsyncChannel.sendMessage(FORGET_NETWORK, netId, putListener(listener));
2213     }
2214 
2215     /**
2216      * Disable network
2217      *
2218      * @param netId is the network Id
2219      * @param listener for callbacks on success or failure. Can be null.
2220      * @throws IllegalStateException if the WifiManager instance needs to be
2221      * initialized again
2222      * @hide
2223      */
2224     public void disable(int netId, ActionListener listener) {
2225         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
2226         validateChannel();
2227         sAsyncChannel.sendMessage(DISABLE_NETWORK, netId, putListener(listener));
2228     }
2229 
2230     /**
2231      * Disable ephemeral Network
2232      *
2233      * @param SSID, in the format of WifiConfiguration's SSID.
2234      * @hide
2235      */
2236     public void disableEphemeralNetwork(String SSID) {
2237         if (SSID == null) throw new IllegalArgumentException("SSID cannot be null");
2238         try {
2239             mService.disableEphemeralNetwork(SSID);
2240         } catch (RemoteException e) {
2241         }
2242     }
2243 
2244     /**
2245      * Start Wi-fi Protected Setup
2246      *
2247      * @param config WPS configuration (does not support {@link WpsInfo#LABEL})
2248      * @param listener for callbacks on success or failure. Can be null.
2249      * @throws IllegalStateException if the WifiManager instance needs to be
2250      * initialized again
2251      */
2252     public void startWps(WpsInfo config, WpsCallback listener) {
2253         if (config == null) throw new IllegalArgumentException("config cannot be null");
2254         validateChannel();
2255         sAsyncChannel.sendMessage(START_WPS, 0, putListener(listener), config);
2256     }
2257 
2258     /**
2259      * Cancel any ongoing Wi-fi Protected Setup
2260      *
2261      * @param listener for callbacks on success or failure. Can be null.
2262      * @throws IllegalStateException if the WifiManager instance needs to be
2263      * initialized again
2264      */
2265     public void cancelWps(WpsCallback listener) {
2266         validateChannel();
2267         sAsyncChannel.sendMessage(CANCEL_WPS, 0, putListener(listener));
2268     }
2269 
2270     /**
2271      * Get a reference to WifiService handler. This is used by a client to establish
2272      * an AsyncChannel communication with WifiService
2273      *
2274      * @return Messenger pointing to the WifiService handler
2275      * @hide
2276      */
2277     public Messenger getWifiServiceMessenger() {
2278         try {
2279             return mService.getWifiServiceMessenger();
2280         } catch (RemoteException e) {
2281             return null;
2282         } catch (SecurityException e) {
2283             return null;
2284         }
2285     }
2286 
2287 
2288     /**
2289      * Returns the file in which IP and proxy configuration data is stored
2290      * @hide
2291      */
2292     public String getConfigFile() {
2293         try {
2294             return mService.getConfigFile();
2295         } catch (RemoteException e) {
2296             return null;
2297         }
2298     }
2299 
2300     /**
2301      * Allows an application to keep the Wi-Fi radio awake.
2302      * Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
2303      * Acquiring a WifiLock will keep the radio on until the lock is released.  Multiple
2304      * applications may hold WifiLocks, and the radio will only be allowed to turn off when no
2305      * WifiLocks are held in any application.
2306      * <p>
2307      * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or
2308      * could function over a mobile network, if available.  A program that needs to download large
2309      * files should hold a WifiLock to ensure that the download will complete, but a program whose
2310      * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely
2311      * affecting battery life.
2312      * <p>
2313      * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane
2314      * Mode.  They simply keep the radio from turning off when Wi-Fi is already on but the device
2315      * is idle.
2316      * <p>
2317      * Any application using a WifiLock must request the {@code android.permission.WAKE_LOCK}
2318      * permission in an {@code &lt;uses-permission&gt;} element of the application's manifest.
2319      */
2320     public class WifiLock {
2321         private String mTag;
2322         private final IBinder mBinder;
2323         private int mRefCount;
2324         int mLockType;
2325         private boolean mRefCounted;
2326         private boolean mHeld;
2327         private WorkSource mWorkSource;
2328 
2329         private WifiLock(int lockType, String tag) {
2330             mTag = tag;
2331             mLockType = lockType;
2332             mBinder = new Binder();
2333             mRefCount = 0;
2334             mRefCounted = true;
2335             mHeld = false;
2336         }
2337 
2338         /**
2339          * Locks the Wi-Fi radio on until {@link #release} is called.
2340          *
2341          * If this WifiLock is reference-counted, each call to {@code acquire} will increment the
2342          * reference count, and the radio will remain locked as long as the reference count is
2343          * above zero.
2344          *
2345          * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock
2346          * the radio, but subsequent calls will be ignored.  Only one call to {@link #release}
2347          * will be required, regardless of the number of times that {@code acquire} is called.
2348          */
2349         public void acquire() {
2350             synchronized (mBinder) {
2351                 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
2352                     try {
2353                         mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource);
2354                         synchronized (WifiManager.this) {
2355                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
2356                                 mService.releaseWifiLock(mBinder);
2357                                 throw new UnsupportedOperationException(
2358                                             "Exceeded maximum number of wifi locks");
2359                             }
2360                             mActiveLockCount++;
2361                         }
2362                     } catch (RemoteException ignore) {
2363                     }
2364                     mHeld = true;
2365                 }
2366             }
2367         }
2368 
2369         /**
2370          * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle.
2371          *
2372          * If this WifiLock is reference-counted, each call to {@code release} will decrement the
2373          * reference count, and the radio will be unlocked only when the reference count reaches
2374          * zero.  If the reference count goes below zero (that is, if {@code release} is called
2375          * a greater number of times than {@link #acquire}), an exception is thrown.
2376          *
2377          * If this WifiLock is not reference-counted, the first call to {@code release} (after
2378          * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent
2379          * calls will be ignored.
2380          */
2381         public void release() {
2382             synchronized (mBinder) {
2383                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
2384                     try {
2385                         mService.releaseWifiLock(mBinder);
2386                         synchronized (WifiManager.this) {
2387                             mActiveLockCount--;
2388                         }
2389                     } catch (RemoteException ignore) {
2390                     }
2391                     mHeld = false;
2392                 }
2393                 if (mRefCount < 0) {
2394                     throw new RuntimeException("WifiLock under-locked " + mTag);
2395                 }
2396             }
2397         }
2398 
2399         /**
2400          * Controls whether this is a reference-counted or non-reference-counted WifiLock.
2401          *
2402          * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and
2403          * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire}
2404          * has been balanced with a call to {@link #release}.  Non-reference-counted WifiLocks
2405          * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the
2406          * radio whenever {@link #release} is called and it is locked.
2407          *
2408          * @param refCounted true if this WifiLock should keep a reference count
2409          */
2410         public void setReferenceCounted(boolean refCounted) {
2411             mRefCounted = refCounted;
2412         }
2413 
2414         /**
2415          * Checks whether this WifiLock is currently held.
2416          *
2417          * @return true if this WifiLock is held, false otherwise
2418          */
2419         public boolean isHeld() {
2420             synchronized (mBinder) {
2421                 return mHeld;
2422             }
2423         }
2424 
2425         public void setWorkSource(WorkSource ws) {
2426             synchronized (mBinder) {
2427                 if (ws != null && ws.size() == 0) {
2428                     ws = null;
2429                 }
2430                 boolean changed = true;
2431                 if (ws == null) {
2432                     mWorkSource = null;
2433                 } else {
2434                     ws.clearNames();
2435                     if (mWorkSource == null) {
2436                         changed = mWorkSource != null;
2437                         mWorkSource = new WorkSource(ws);
2438                     } else {
2439                         changed = mWorkSource.diff(ws);
2440                         if (changed) {
2441                             mWorkSource.set(ws);
2442                         }
2443                     }
2444                 }
2445                 if (changed && mHeld) {
2446                     try {
2447                         mService.updateWifiLockWorkSource(mBinder, mWorkSource);
2448                     } catch (RemoteException e) {
2449                     }
2450                 }
2451             }
2452         }
2453 
2454         public String toString() {
2455             String s1, s2, s3;
2456             synchronized (mBinder) {
2457                 s1 = Integer.toHexString(System.identityHashCode(this));
2458                 s2 = mHeld ? "held; " : "";
2459                 if (mRefCounted) {
2460                     s3 = "refcounted: refcount = " + mRefCount;
2461                 } else {
2462                     s3 = "not refcounted";
2463                 }
2464                 return "WifiLock{ " + s1 + "; " + s2 + s3 + " }";
2465             }
2466         }
2467 
2468         @Override
2469         protected void finalize() throws Throwable {
2470             super.finalize();
2471             synchronized (mBinder) {
2472                 if (mHeld) {
2473                     try {
2474                         mService.releaseWifiLock(mBinder);
2475                         synchronized (WifiManager.this) {
2476                             mActiveLockCount--;
2477                         }
2478                     } catch (RemoteException ignore) {
2479                     }
2480                 }
2481             }
2482         }
2483     }
2484 
2485     /**
2486      * Creates a new WifiLock.
2487      *
2488      * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL},
2489      * {@link #WIFI_MODE_FULL_HIGH_PERF} and {@link #WIFI_MODE_SCAN_ONLY} for
2490      * descriptions of the types of Wi-Fi locks.
2491      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
2492      *            never shown to the user under normal conditions, but should be descriptive
2493      *            enough to identify your application and the specific WifiLock within it, if it
2494      *            holds multiple WifiLocks.
2495      *
2496      * @return a new, unacquired WifiLock with the given tag.
2497      *
2498      * @see WifiLock
2499      */
2500     public WifiLock createWifiLock(int lockType, String tag) {
2501         return new WifiLock(lockType, tag);
2502     }
2503 
2504     /**
2505      * Creates a new WifiLock.
2506      *
2507      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
2508      *            never shown to the user under normal conditions, but should be descriptive
2509      *            enough to identify your application and the specific WifiLock within it, if it
2510      *            holds multiple WifiLocks.
2511      *
2512      * @return a new, unacquired WifiLock with the given tag.
2513      *
2514      * @see WifiLock
2515      */
2516     public WifiLock createWifiLock(String tag) {
2517         return new WifiLock(WIFI_MODE_FULL, tag);
2518     }
2519 
2520 
2521     /**
2522      * Create a new MulticastLock
2523      *
2524      * @param tag a tag for the MulticastLock to identify it in debugging
2525      *            messages.  This string is never shown to the user under
2526      *            normal conditions, but should be descriptive enough to
2527      *            identify your application and the specific MulticastLock
2528      *            within it, if it holds multiple MulticastLocks.
2529      *
2530      * @return a new, unacquired MulticastLock with the given tag.
2531      *
2532      * @see MulticastLock
2533      */
2534     public MulticastLock createMulticastLock(String tag) {
2535         return new MulticastLock(tag);
2536     }
2537 
2538     /**
2539      * Allows an application to receive Wifi Multicast packets.
2540      * Normally the Wifi stack filters out packets not explicitly
2541      * addressed to this device.  Acquring a MulticastLock will
2542      * cause the stack to receive packets addressed to multicast
2543      * addresses.  Processing these extra packets can cause a noticable
2544      * battery drain and should be disabled when not needed.
2545      */
2546     public class MulticastLock {
2547         private String mTag;
2548         private final IBinder mBinder;
2549         private int mRefCount;
2550         private boolean mRefCounted;
2551         private boolean mHeld;
2552 
2553         private MulticastLock(String tag) {
2554             mTag = tag;
2555             mBinder = new Binder();
2556             mRefCount = 0;
2557             mRefCounted = true;
2558             mHeld = false;
2559         }
2560 
2561         /**
2562          * Locks Wifi Multicast on until {@link #release} is called.
2563          *
2564          * If this MulticastLock is reference-counted each call to
2565          * {@code acquire} will increment the reference count, and the
2566          * wifi interface will receive multicast packets as long as the
2567          * reference count is above zero.
2568          *
2569          * If this MulticastLock is not reference-counted, the first call to
2570          * {@code acquire} will turn on the multicast packets, but subsequent
2571          * calls will be ignored.  Only one call to {@link #release} will
2572          * be required, regardless of the number of times that {@code acquire}
2573          * is called.
2574          *
2575          * Note that other applications may also lock Wifi Multicast on.
2576          * Only they can relinquish their lock.
2577          *
2578          * Also note that applications cannot leave Multicast locked on.
2579          * When an app exits or crashes, any Multicast locks will be released.
2580          */
2581         public void acquire() {
2582             synchronized (mBinder) {
2583                 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
2584                     try {
2585                         mService.acquireMulticastLock(mBinder, mTag);
2586                         synchronized (WifiManager.this) {
2587                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
2588                                 mService.releaseMulticastLock();
2589                                 throw new UnsupportedOperationException(
2590                                         "Exceeded maximum number of wifi locks");
2591                             }
2592                             mActiveLockCount++;
2593                         }
2594                     } catch (RemoteException ignore) {
2595                     }
2596                     mHeld = true;
2597                 }
2598             }
2599         }
2600 
2601         /**
2602          * Unlocks Wifi Multicast, restoring the filter of packets
2603          * not addressed specifically to this device and saving power.
2604          *
2605          * If this MulticastLock is reference-counted, each call to
2606          * {@code release} will decrement the reference count, and the
2607          * multicast packets will only stop being received when the reference
2608          * count reaches zero.  If the reference count goes below zero (that
2609          * is, if {@code release} is called a greater number of times than
2610          * {@link #acquire}), an exception is thrown.
2611          *
2612          * If this MulticastLock is not reference-counted, the first call to
2613          * {@code release} (after the radio was multicast locked using
2614          * {@link #acquire}) will unlock the multicast, and subsequent calls
2615          * will be ignored.
2616          *
2617          * Note that if any other Wifi Multicast Locks are still outstanding
2618          * this {@code release} call will not have an immediate effect.  Only
2619          * when all applications have released all their Multicast Locks will
2620          * the Multicast filter be turned back on.
2621          *
2622          * Also note that when an app exits or crashes all of its Multicast
2623          * Locks will be automatically released.
2624          */
2625         public void release() {
2626             synchronized (mBinder) {
2627                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
2628                     try {
2629                         mService.releaseMulticastLock();
2630                         synchronized (WifiManager.this) {
2631                             mActiveLockCount--;
2632                         }
2633                     } catch (RemoteException ignore) {
2634                     }
2635                     mHeld = false;
2636                 }
2637                 if (mRefCount < 0) {
2638                     throw new RuntimeException("MulticastLock under-locked "
2639                             + mTag);
2640                 }
2641             }
2642         }
2643 
2644         /**
2645          * Controls whether this is a reference-counted or non-reference-
2646          * counted MulticastLock.
2647          *
2648          * Reference-counted MulticastLocks keep track of the number of calls
2649          * to {@link #acquire} and {@link #release}, and only stop the
2650          * reception of multicast packets when every call to {@link #acquire}
2651          * has been balanced with a call to {@link #release}.  Non-reference-
2652          * counted MulticastLocks allow the reception of multicast packets
2653          * whenever {@link #acquire} is called and stop accepting multicast
2654          * packets whenever {@link #release} is called.
2655          *
2656          * @param refCounted true if this MulticastLock should keep a reference
2657          * count
2658          */
2659         public void setReferenceCounted(boolean refCounted) {
2660             mRefCounted = refCounted;
2661         }
2662 
2663         /**
2664          * Checks whether this MulticastLock is currently held.
2665          *
2666          * @return true if this MulticastLock is held, false otherwise
2667          */
2668         public boolean isHeld() {
2669             synchronized (mBinder) {
2670                 return mHeld;
2671             }
2672         }
2673 
2674         public String toString() {
2675             String s1, s2, s3;
2676             synchronized (mBinder) {
2677                 s1 = Integer.toHexString(System.identityHashCode(this));
2678                 s2 = mHeld ? "held; " : "";
2679                 if (mRefCounted) {
2680                     s3 = "refcounted: refcount = " + mRefCount;
2681                 } else {
2682                     s3 = "not refcounted";
2683                 }
2684                 return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }";
2685             }
2686         }
2687 
2688         @Override
2689         protected void finalize() throws Throwable {
2690             super.finalize();
2691             setReferenceCounted(false);
2692             release();
2693         }
2694     }
2695 
2696     /**
2697      * Check multicast filter status.
2698      *
2699      * @return true if multicast packets are allowed.
2700      *
2701      * @hide pending API council approval
2702      */
2703     public boolean isMulticastEnabled() {
2704         try {
2705             return mService.isMulticastEnabled();
2706         } catch (RemoteException e) {
2707             return false;
2708         }
2709     }
2710 
2711     /**
2712      * Initialize the multicast filtering to 'on'
2713      * @hide no intent to publish
2714      */
2715     public boolean initializeMulticastFiltering() {
2716         try {
2717             mService.initializeMulticastFiltering();
2718             return true;
2719         } catch (RemoteException e) {
2720              return false;
2721         }
2722     }
2723 
2724     protected void finalize() throws Throwable {
2725         try {
2726             synchronized (sThreadRefLock) {
2727                 if (--sThreadRefCount == 0 && sAsyncChannel != null) {
2728                     sAsyncChannel.disconnect();
2729                 }
2730             }
2731         } finally {
2732             super.finalize();
2733         }
2734     }
2735 
2736     /**
2737      * Set wifi verbose log. Called from developer settings.
2738      * @hide
2739      */
2740     public void enableVerboseLogging (int verbose) {
2741         try {
2742             mService.enableVerboseLogging(verbose);
2743         } catch (Exception e) {
2744             //ignore any failure here
2745             Log.e(TAG, "enableVerboseLogging " + e.toString());
2746         }
2747     }
2748 
2749     /**
2750      * Get the WiFi verbose logging level.This is used by settings
2751      * to decide what to show within the picker.
2752      * @hide
2753      */
2754     public int getVerboseLoggingLevel() {
2755         try {
2756             return mService.getVerboseLoggingLevel();
2757         } catch (RemoteException e) {
2758             return 0;
2759         }
2760     }
2761 
2762     /**
2763      * Set wifi Aggressive Handover. Called from developer settings.
2764      * @hide
2765      */
2766     public void enableAggressiveHandover(int enabled) {
2767         try {
2768             mService.enableAggressiveHandover(enabled);
2769         } catch (RemoteException e) {
2770 
2771         }
2772     }
2773 
2774     /**
2775      * Get the WiFi Handover aggressiveness.This is used by settings
2776      * to decide what to show within the picker.
2777      * @hide
2778      */
2779     public int getAggressiveHandover() {
2780         try {
2781             return mService.getAggressiveHandover();
2782         } catch (RemoteException e) {
2783             return 0;
2784         }
2785     }
2786 
2787     /**
2788      * Set setting for allowing Scans when traffic is ongoing.
2789      * @hide
2790      */
2791     public void setAllowScansWithTraffic(int enabled) {
2792         try {
2793             mService.setAllowScansWithTraffic(enabled);
2794         } catch (RemoteException e) {
2795 
2796         }
2797     }
2798 
2799     /**
2800      * Get setting for allowing Scans when traffic is ongoing.
2801      * @hide
2802      */
2803     public int getAllowScansWithTraffic() {
2804         try {
2805             return mService.getAllowScansWithTraffic();
2806         } catch (RemoteException e) {
2807             return 0;
2808         }
2809     }
2810 
2811     /**
2812      * Resets all wifi manager settings back to factory defaults.
2813      *
2814      * @hide
2815      */
2816     public void factoryReset() {
2817         try {
2818             mService.factoryReset();
2819         } catch (RemoteException e) {
2820         }
2821     }
2822 
2823     /**
2824      * Get Network object of current wifi network
2825      * @return Get Network object of current wifi network
2826      * @hide
2827      */
2828     public Network getCurrentNetwork() {
2829         try {
2830             return mService.getCurrentNetwork();
2831         } catch (RemoteException e) {
2832             return null;
2833         }
2834     }
2835 
2836     /**
2837      * Framework layer autojoin enable/disable when device is associated
2838      * this will enable/disable autojoin scan and switch network when connected
2839      * @return true -- if set successful false -- if set failed
2840      * @hide
2841      */
2842     public boolean enableAutoJoinWhenAssociated(boolean enabled) {
2843         try {
2844             return mService.enableAutoJoinWhenAssociated(enabled);
2845         } catch (RemoteException e) {
2846             return false;
2847         }
2848     }
2849 
2850     /**
2851      * Get setting for Framework layer autojoin enable status
2852      * @hide
2853      */
2854     public boolean getEnableAutoJoinWhenAssociated() {
2855         try {
2856             return mService.getEnableAutoJoinWhenAssociated();
2857         } catch (RemoteException e) {
2858             return false;
2859         }
2860     }
2861     /**
2862      * Set setting for enabling autojoin Offload thru Wifi HAL layer
2863      * @hide
2864      */
2865     public void setHalBasedAutojoinOffload(int enabled) {
2866         try {
2867             mService.setHalBasedAutojoinOffload(enabled);
2868         } catch (RemoteException e) {
2869 
2870         }
2871     }
2872 
2873     /**
2874      * Get setting for enabling autojoin Offload thru Wifi HAL layer
2875      * @hide
2876      */
2877     public int getHalBasedAutojoinOffload() {
2878         try {
2879             return mService.getHalBasedAutojoinOffload();
2880         } catch (RemoteException e) {
2881         }
2882         return 0;
2883     }
2884 }
2885