1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.net.wifi;
18
19import android.annotation.SdkConstant;
20import android.annotation.SdkConstant.SdkConstantType;
21import android.annotation.SystemApi;
22import android.content.Context;
23import android.net.ConnectivityManager;
24import android.net.ConnectivityManager.NetworkCallback;
25import android.net.DhcpInfo;
26import android.net.Network;
27import android.net.NetworkCapabilities;
28import android.net.NetworkRequest;
29import android.net.wifi.ScanSettings;
30import android.net.wifi.WifiChannel;
31import android.os.Binder;
32import android.os.Build;
33import android.os.IBinder;
34import android.os.Handler;
35import android.os.HandlerThread;
36import android.os.Looper;
37import android.os.Message;
38import android.os.RemoteException;
39import android.os.WorkSource;
40import android.os.Messenger;
41import android.util.Log;
42import android.util.SparseArray;
43
44import java.net.InetAddress;
45import java.util.concurrent.CountDownLatch;
46
47import com.android.internal.annotations.GuardedBy;
48import com.android.internal.util.AsyncChannel;
49import com.android.internal.util.Protocol;
50
51import 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 */
74public 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     */
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     */
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
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
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     */
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     */
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     */
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     */
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     */
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     */
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