WifiManager.java revision d3975a917799b85cacaf382b65c5832813066b51
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.content.Context;
22import android.net.DhcpInfo;
23import android.os.Binder;
24import android.os.IBinder;
25import android.os.Handler;
26import android.os.Looper;
27import android.os.Message;
28import android.os.RemoteException;
29import android.os.WorkSource;
30import android.os.Messenger;
31import android.util.SparseArray;
32
33import com.android.internal.util.AsyncChannel;
34import com.android.internal.util.Protocol;
35
36import java.util.List;
37
38/**
39 * This class provides the primary API for managing all aspects of Wi-Fi
40 * connectivity. Get an instance of this class by calling
41 * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.WIFI_SERVICE)}.
42
43 * It deals with several categories of items:
44 * <ul>
45 * <li>The list of configured networks. The list can be viewed and updated,
46 * and attributes of individual entries can be modified.</li>
47 * <li>The currently active Wi-Fi network, if any. Connectivity can be
48 * established or torn down, and dynamic information about the state of
49 * the network can be queried.</li>
50 * <li>Results of access point scans, containing enough information to
51 * make decisions about what access point to connect to.</li>
52 * <li>It defines the names of various Intent actions that are broadcast
53 * upon any sort of change in Wi-Fi state.
54 * </ul>
55 * This is the API to use when performing Wi-Fi specific operations. To
56 * perform operations that pertain to network connectivity at an abstract
57 * level, use {@link android.net.ConnectivityManager}.
58 */
59public class WifiManager {
60
61    // Supplicant error codes:
62    /**
63     * The error code if there was a problem authenticating.
64     */
65    public static final int ERROR_AUTHENTICATING = 1;
66
67    /**
68     * Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
69     * enabling, disabling, or unknown. One extra provides this state as an int.
70     * Another extra provides the previous state, if available.
71     *
72     * @see #EXTRA_WIFI_STATE
73     * @see #EXTRA_PREVIOUS_WIFI_STATE
74     */
75    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
76    public static final String WIFI_STATE_CHANGED_ACTION =
77        "android.net.wifi.WIFI_STATE_CHANGED";
78    /**
79     * The lookup key for an int that indicates whether Wi-Fi is enabled,
80     * disabled, enabling, disabling, or unknown.  Retrieve it with
81     * {@link android.content.Intent#getIntExtra(String,int)}.
82     *
83     * @see #WIFI_STATE_DISABLED
84     * @see #WIFI_STATE_DISABLING
85     * @see #WIFI_STATE_ENABLED
86     * @see #WIFI_STATE_ENABLING
87     * @see #WIFI_STATE_UNKNOWN
88     */
89    public static final String EXTRA_WIFI_STATE = "wifi_state";
90    /**
91     * The previous Wi-Fi state.
92     *
93     * @see #EXTRA_WIFI_STATE
94     */
95    public static final String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
96
97    /**
98     * Wi-Fi is currently being disabled. The state will change to {@link #WIFI_STATE_DISABLED} if
99     * it finishes successfully.
100     *
101     * @see #WIFI_STATE_CHANGED_ACTION
102     * @see #getWifiState()
103     */
104    public static final int WIFI_STATE_DISABLING = 0;
105    /**
106     * Wi-Fi is disabled.
107     *
108     * @see #WIFI_STATE_CHANGED_ACTION
109     * @see #getWifiState()
110     */
111    public static final int WIFI_STATE_DISABLED = 1;
112    /**
113     * Wi-Fi is currently being enabled. The state will change to {@link #WIFI_STATE_ENABLED} if
114     * it finishes successfully.
115     *
116     * @see #WIFI_STATE_CHANGED_ACTION
117     * @see #getWifiState()
118     */
119    public static final int WIFI_STATE_ENABLING = 2;
120    /**
121     * Wi-Fi is enabled.
122     *
123     * @see #WIFI_STATE_CHANGED_ACTION
124     * @see #getWifiState()
125     */
126    public static final int WIFI_STATE_ENABLED = 3;
127    /**
128     * Wi-Fi is in an unknown state. This state will occur when an error happens while enabling
129     * or disabling.
130     *
131     * @see #WIFI_STATE_CHANGED_ACTION
132     * @see #getWifiState()
133     */
134    public static final int WIFI_STATE_UNKNOWN = 4;
135
136    /**
137     * Broadcast intent action indicating that Wi-Fi AP has been enabled, disabled,
138     * enabling, disabling, or failed.
139     *
140     * @hide
141     */
142    public static final String WIFI_AP_STATE_CHANGED_ACTION =
143        "android.net.wifi.WIFI_AP_STATE_CHANGED";
144
145    /**
146     * The lookup key for an int that indicates whether Wi-Fi AP is enabled,
147     * disabled, enabling, disabling, or failed.  Retrieve it with
148     * {@link android.content.Intent#getIntExtra(String,int)}.
149     *
150     * @see #WIFI_AP_STATE_DISABLED
151     * @see #WIFI_AP_STATE_DISABLING
152     * @see #WIFI_AP_STATE_ENABLED
153     * @see #WIFI_AP_STATE_ENABLING
154     * @see #WIFI_AP_STATE_FAILED
155     *
156     * @hide
157     */
158    public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
159    /**
160     * The previous Wi-Fi state.
161     *
162     * @see #EXTRA_WIFI_AP_STATE
163     *
164     * @hide
165     */
166    public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
167    /**
168     * Wi-Fi AP is currently being disabled. The state will change to
169     * {@link #WIFI_AP_STATE_DISABLED} if it finishes successfully.
170     *
171     * @see #WIFI_AP_STATE_CHANGED_ACTION
172     * @see #getWifiApState()
173     *
174     * @hide
175     */
176    public static final int WIFI_AP_STATE_DISABLING = 10;
177    /**
178     * Wi-Fi AP is disabled.
179     *
180     * @see #WIFI_AP_STATE_CHANGED_ACTION
181     * @see #getWifiState()
182     *
183     * @hide
184     */
185    public static final int WIFI_AP_STATE_DISABLED = 11;
186    /**
187     * Wi-Fi AP is currently being enabled. The state will change to
188     * {@link #WIFI_AP_STATE_ENABLED} if it finishes successfully.
189     *
190     * @see #WIFI_AP_STATE_CHANGED_ACTION
191     * @see #getWifiApState()
192     *
193     * @hide
194     */
195    public static final int WIFI_AP_STATE_ENABLING = 12;
196    /**
197     * Wi-Fi AP is enabled.
198     *
199     * @see #WIFI_AP_STATE_CHANGED_ACTION
200     * @see #getWifiApState()
201     *
202     * @hide
203     */
204    public static final int WIFI_AP_STATE_ENABLED = 13;
205    /**
206     * Wi-Fi AP is in a failed state. This state will occur when an error occurs during
207     * enabling or disabling
208     *
209     * @see #WIFI_AP_STATE_CHANGED_ACTION
210     * @see #getWifiApState()
211     *
212     * @hide
213     */
214    public static final int WIFI_AP_STATE_FAILED = 14;
215
216    /**
217     * Broadcast intent action indicating that a connection to the supplicant has
218     * been established (and it is now possible
219     * to perform Wi-Fi operations) or the connection to the supplicant has been
220     * lost. One extra provides the connection state as a boolean, where {@code true}
221     * means CONNECTED.
222     * @see #EXTRA_SUPPLICANT_CONNECTED
223     */
224    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
225    public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION =
226        "android.net.wifi.supplicant.CONNECTION_CHANGE";
227    /**
228     * The lookup key for a boolean that indicates whether a connection to
229     * the supplicant daemon has been gained or lost. {@code true} means
230     * a connection now exists.
231     * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
232     */
233    public static final String EXTRA_SUPPLICANT_CONNECTED = "connected";
234    /**
235     * Broadcast intent action indicating that the state of Wi-Fi connectivity
236     * has changed. One extra provides the new state
237     * in the form of a {@link android.net.NetworkInfo} object. If the new
238     * state is CONNECTED, additional extras may provide the BSSID and WifiInfo of
239     * the access point.
240     * as a {@code String}.
241     * @see #EXTRA_NETWORK_INFO
242     * @see #EXTRA_BSSID
243     * @see #EXTRA_WIFI_INFO
244     */
245    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
246    public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
247    /**
248     * The lookup key for a {@link android.net.NetworkInfo} object associated with the
249     * Wi-Fi network. Retrieve with
250     * {@link android.content.Intent#getParcelableExtra(String)}.
251     */
252    public static final String EXTRA_NETWORK_INFO = "networkInfo";
253    /**
254     * The lookup key for a String giving the BSSID of the access point to which
255     * we are connected. Only present when the new state is CONNECTED.
256     * Retrieve with
257     * {@link android.content.Intent#getStringExtra(String)}.
258     */
259    public static final String EXTRA_BSSID = "bssid";
260    /**
261     * The lookup key for a {@link android.net.wifi.WifiInfo} object giving the
262     * information about the access point to which we are connected. Only present
263     * when the new state is CONNECTED.  Retrieve with
264     * {@link android.content.Intent#getParcelableExtra(String)}.
265     */
266    public static final String EXTRA_WIFI_INFO = "wifiInfo";
267    /**
268     * Broadcast intent action indicating that the state of establishing a connection to
269     * an access point has changed.One extra provides the new
270     * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and
271     * is not generally the most useful thing to look at if you are just interested in
272     * the overall state of connectivity.
273     * @see #EXTRA_NEW_STATE
274     * @see #EXTRA_SUPPLICANT_ERROR
275     */
276    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
277    public static final String SUPPLICANT_STATE_CHANGED_ACTION =
278        "android.net.wifi.supplicant.STATE_CHANGE";
279    /**
280     * The lookup key for a {@link SupplicantState} describing the new state
281     * Retrieve with
282     * {@link android.content.Intent#getParcelableExtra(String)}.
283     */
284    public static final String EXTRA_NEW_STATE = "newState";
285
286    /**
287     * The lookup key for a {@link SupplicantState} describing the supplicant
288     * error code if any
289     * Retrieve with
290     * {@link android.content.Intent#getIntExtra(String, int)}.
291     * @see #ERROR_AUTHENTICATING
292     */
293    public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError";
294
295    /**
296     * Broadcast intent action indicating that the configured networks changed.
297     * This can be as a result of adding/updating/deleting a network
298     * @hide
299     */
300    public static final String CONFIGURED_NETWORKS_CHANGED_ACTION =
301        "android.net.wifi.CONFIGURED_NETWORKS_CHANGE";
302    /**
303     * An access point scan has completed, and results are available from the supplicant.
304     * Call {@link #getScanResults()} to obtain the results.
305     */
306    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
307    public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
308    /**
309     * The RSSI (signal strength) has changed.
310     * @see #EXTRA_NEW_RSSI
311     */
312    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
313    public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
314    /**
315     * The lookup key for an {@code int} giving the new RSSI in dBm.
316     */
317    public static final String EXTRA_NEW_RSSI = "newRssi";
318
319    /**
320     * Broadcast intent action indicating that the link configuration
321     * changed on wifi.
322     * @hide
323     */
324    public static final String LINK_CONFIGURATION_CHANGED_ACTION =
325        "android.net.wifi.LINK_CONFIGURATION_CHANGED";
326
327    /**
328     * The lookup key for a {@link android.net.LinkProperties} object associated with the
329     * Wi-Fi network. Retrieve with
330     * {@link android.content.Intent#getParcelableExtra(String)}.
331     * @hide
332     */
333    public static final String EXTRA_LINK_PROPERTIES = "linkProperties";
334
335    /**
336     * The lookup key for a {@link android.net.LinkCapabilities} object associated with the
337     * Wi-Fi network. Retrieve with
338     * {@link android.content.Intent#getParcelableExtra(String)}.
339     * @hide
340     */
341    public static final String EXTRA_LINK_CAPABILITIES = "linkCapabilities";
342
343    /**
344     * The network IDs of the configured networks could have changed.
345     */
346    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
347    public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
348
349    /**
350     * Activity Action: Pick a Wi-Fi network to connect to.
351     * <p>Input: Nothing.
352     * <p>Output: Nothing.
353     */
354    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
355    public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
356
357    /**
358     * In this Wi-Fi lock mode, Wi-Fi will be kept active,
359     * and will behave normally, i.e., it will attempt to automatically
360     * establish a connection to a remembered access point that is
361     * within range, and will do periodic scans if there are remembered
362     * access points but none are in range.
363     */
364    public static final int WIFI_MODE_FULL = 1;
365    /**
366     * In this Wi-Fi lock mode, Wi-Fi will be kept active,
367     * but the only operation that will be supported is initiation of
368     * scans, and the subsequent reporting of scan results. No attempts
369     * will be made to automatically connect to remembered access points,
370     * nor will periodic scans be automatically performed looking for
371     * remembered access points. Scans must be explicitly requested by
372     * an application in this mode.
373     */
374    public static final int WIFI_MODE_SCAN_ONLY = 2;
375    /**
376     * In this Wi-Fi lock mode, Wi-Fi will be kept active as in mode
377     * {@link #WIFI_MODE_FULL} but it operates at high performance
378     * with minimum packet loss and low packet latency even when
379     * the device screen is off. This mode will consume more power
380     * and hence should be used only when there is a need for such
381     * an active connection.
382     * <p>
383     * An example use case is when a voice connection needs to be
384     * kept active even after the device screen goes off. Holding the
385     * regular {@link #WIFI_MODE_FULL} lock will keep the wifi
386     * connection active, but the connection can be lossy.
387     * Holding a {@link #WIFI_MODE_FULL_HIGH_PERF} lock for the
388     * duration of the voice call will improve the call quality.
389     * <p>
390     * When there is no support from the hardware, this lock mode
391     * will have the same behavior as {@link #WIFI_MODE_FULL}
392     */
393    public static final int WIFI_MODE_FULL_HIGH_PERF = 3;
394
395    /** Anything worse than or equal to this will show 0 bars. */
396    private static final int MIN_RSSI = -100;
397
398    /** Anything better than or equal to this will show the max bars. */
399    private static final int MAX_RSSI = -55;
400
401    /**
402     * Number of RSSI levels used in the framework to initiate
403     * {@link #RSSI_CHANGED_ACTION} broadcast
404     * @hide
405     */
406    public static final int RSSI_LEVELS = 5;
407
408    /**
409     * Auto settings in the driver. The driver could choose to operate on both
410     * 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band.
411     * @hide
412     */
413    public static final int WIFI_FREQUENCY_BAND_AUTO = 0;
414
415    /**
416     * Operation on 5 GHz alone
417     * @hide
418     */
419    public static final int WIFI_FREQUENCY_BAND_5GHZ = 1;
420
421    /**
422     * Operation on 2.4 GHz alone
423     * @hide
424     */
425    public static final int WIFI_FREQUENCY_BAND_2GHZ = 2;
426
427    /** List of asyncronous notifications
428     * @hide
429     */
430    public static final int DATA_ACTIVITY_NOTIFICATION = 1;
431
432    //Lowest bit indicates data reception and the second lowest
433    //bit indicates data transmitted
434    /** @hide */
435    public static final int DATA_ACTIVITY_NONE         = 0x00;
436    /** @hide */
437    public static final int DATA_ACTIVITY_IN           = 0x01;
438    /** @hide */
439    public static final int DATA_ACTIVITY_OUT          = 0x02;
440    /** @hide */
441    public static final int DATA_ACTIVITY_INOUT        = 0x03;
442
443    IWifiManager mService;
444    Handler mHandler;
445
446    /* Maximum number of active locks we allow.
447     * This limit was added to prevent apps from creating a ridiculous number
448     * of locks and crashing the system by overflowing the global ref table.
449     */
450    private static final int MAX_ACTIVE_LOCKS = 50;
451
452    /* Number of currently active WifiLocks and MulticastLocks */
453    private int mActiveLockCount;
454
455    /**
456     * Create a new WifiManager instance.
457     * Applications will almost always want to use
458     * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
459     * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
460     * @param service the Binder interface
461     * @param handler target for messages
462     * @hide - hide this because it takes in a parameter of type IWifiManager, which
463     * is a system private class.
464     */
465    public WifiManager(IWifiManager service, Handler handler) {
466        mService = service;
467        mHandler = handler;
468    }
469
470    /**
471     * Return a list of all the networks configured in the supplicant.
472     * Not all fields of WifiConfiguration are returned. Only the following
473     * fields are filled in:
474     * <ul>
475     * <li>networkId</li>
476     * <li>SSID</li>
477     * <li>BSSID</li>
478     * <li>priority</li>
479     * <li>allowedProtocols</li>
480     * <li>allowedKeyManagement</li>
481     * <li>allowedAuthAlgorithms</li>
482     * <li>allowedPairwiseCiphers</li>
483     * <li>allowedGroupCiphers</li>
484     * </ul>
485     * @return a list of network configurations in the form of a list
486     * of {@link WifiConfiguration} objects.
487     */
488    public List<WifiConfiguration> getConfiguredNetworks() {
489        try {
490            return mService.getConfiguredNetworks();
491        } catch (RemoteException e) {
492            return null;
493        }
494    }
495
496    /**
497     * Add a new network description to the set of configured networks.
498     * The {@code networkId} field of the supplied configuration object
499     * is ignored.
500     * <p/>
501     * The new network will be marked DISABLED by default. To enable it,
502     * called {@link #enableNetwork}.
503     *
504     * @param config the set of variables that describe the configuration,
505     *            contained in a {@link WifiConfiguration} object.
506     * @return the ID of the newly created network description. This is used in
507     *         other operations to specified the network to be acted upon.
508     *         Returns {@code -1} on failure.
509     */
510    public int addNetwork(WifiConfiguration config) {
511        if (config == null) {
512            return -1;
513        }
514        config.networkId = -1;
515        return addOrUpdateNetwork(config);
516    }
517
518    /**
519     * Update the network description of an existing configured network.
520     *
521     * @param config the set of variables that describe the configuration,
522     *            contained in a {@link WifiConfiguration} object. It may
523     *            be sparse, so that only the items that are being changed
524     *            are non-<code>null</code>. The {@code networkId} field
525     *            must be set to the ID of the existing network being updated.
526     * @return Returns the {@code networkId} of the supplied
527     *         {@code WifiConfiguration} on success.
528     *         <br/>
529     *         Returns {@code -1} on failure, including when the {@code networkId}
530     *         field of the {@code WifiConfiguration} does not refer to an
531     *         existing network.
532     */
533    public int updateNetwork(WifiConfiguration config) {
534        if (config == null || config.networkId < 0) {
535            return -1;
536        }
537        return addOrUpdateNetwork(config);
538    }
539
540    /**
541     * Internal method for doing the RPC that creates a new network description
542     * or updates an existing one.
543     *
544     * @param config The possibly sparse object containing the variables that
545     *         are to set or updated in the network description.
546     * @return the ID of the network on success, {@code -1} on failure.
547     */
548    private int addOrUpdateNetwork(WifiConfiguration config) {
549        try {
550            return mService.addOrUpdateNetwork(config);
551        } catch (RemoteException e) {
552            return -1;
553        }
554    }
555
556    /**
557     * Remove the specified network from the list of configured networks.
558     * This may result in the asynchronous delivery of state change
559     * events.
560     * @param netId the integer that identifies the network configuration
561     * to the supplicant
562     * @return {@code true} if the operation succeeded
563     */
564    public boolean removeNetwork(int netId) {
565        try {
566            return mService.removeNetwork(netId);
567        } catch (RemoteException e) {
568            return false;
569        }
570    }
571
572    /**
573     * Allow a previously configured network to be associated with. If
574     * <code>disableOthers</code> is true, then all other configured
575     * networks are disabled, and an attempt to connect to the selected
576     * network is initiated. This may result in the asynchronous delivery
577     * of state change events.
578     * @param netId the ID of the network in the list of configured networks
579     * @param disableOthers if true, disable all other networks. The way to
580     * select a particular network to connect to is specify {@code true}
581     * for this parameter.
582     * @return {@code true} if the operation succeeded
583     */
584    public boolean enableNetwork(int netId, boolean disableOthers) {
585        try {
586            return mService.enableNetwork(netId, disableOthers);
587        } catch (RemoteException e) {
588            return false;
589        }
590    }
591
592    /**
593     * Disable a configured network. The specified network will not be
594     * a candidate for associating. This may result in the asynchronous
595     * delivery of state change events.
596     * @param netId the ID of the network as returned by {@link #addNetwork}.
597     * @return {@code true} if the operation succeeded
598     */
599    public boolean disableNetwork(int netId) {
600        try {
601            return mService.disableNetwork(netId);
602        } catch (RemoteException e) {
603            return false;
604        }
605    }
606
607    /**
608     * Disassociate from the currently active access point. This may result
609     * in the asynchronous delivery of state change events.
610     * @return {@code true} if the operation succeeded
611     */
612    public boolean disconnect() {
613        try {
614            mService.disconnect();
615            return true;
616        } catch (RemoteException e) {
617            return false;
618        }
619    }
620
621    /**
622     * Reconnect to the currently active access point, if we are currently
623     * disconnected. This may result in the asynchronous delivery of state
624     * change events.
625     * @return {@code true} if the operation succeeded
626     */
627    public boolean reconnect() {
628        try {
629            mService.reconnect();
630            return true;
631        } catch (RemoteException e) {
632            return false;
633        }
634    }
635
636    /**
637     * Reconnect to the currently active access point, even if we are already
638     * connected. This may result in the asynchronous delivery of state
639     * change events.
640     * @return {@code true} if the operation succeeded
641     */
642    public boolean reassociate() {
643        try {
644            mService.reassociate();
645            return true;
646        } catch (RemoteException e) {
647            return false;
648        }
649    }
650
651    /**
652     * Check that the supplicant daemon is responding to requests.
653     * @return {@code true} if we were able to communicate with the supplicant and
654     * it returned the expected response to the PING message.
655     */
656    public boolean pingSupplicant() {
657        if (mService == null)
658            return false;
659        try {
660            return mService.pingSupplicant();
661        } catch (RemoteException e) {
662            return false;
663        }
664    }
665
666    /**
667     * Request a scan for access points. Returns immediately. The availability
668     * of the results is made known later by means of an asynchronous event sent
669     * on completion of the scan.
670     * @return {@code true} if the operation succeeded, i.e., the scan was initiated
671     */
672    public boolean startScan() {
673        try {
674            mService.startScan(false);
675            return true;
676        } catch (RemoteException e) {
677            return false;
678        }
679    }
680
681    /**
682     * Request a scan for access points. Returns immediately. The availability
683     * of the results is made known later by means of an asynchronous event sent
684     * on completion of the scan.
685     * This is a variant of startScan that forces an active scan, even if passive
686     * scans are the current default
687     * @return {@code true} if the operation succeeded, i.e., the scan was initiated
688     *
689     * @hide
690     */
691    public boolean startScanActive() {
692        try {
693            mService.startScan(true);
694            return true;
695        } catch (RemoteException e) {
696            return false;
697        }
698    }
699
700    /**
701     * Return dynamic information about the current Wi-Fi connection, if any is active.
702     * @return the Wi-Fi information, contained in {@link WifiInfo}.
703     */
704    public WifiInfo getConnectionInfo() {
705        try {
706            return mService.getConnectionInfo();
707        } catch (RemoteException e) {
708            return null;
709        }
710    }
711
712    /**
713     * Return the results of the latest access point scan.
714     * @return the list of access points found in the most recent scan.
715     */
716    public List<ScanResult> getScanResults() {
717        try {
718            return mService.getScanResults();
719        } catch (RemoteException e) {
720            return null;
721        }
722    }
723
724    /**
725     * Tell the supplicant to persist the current list of configured networks.
726     * <p>
727     * Note: It is possible for this method to change the network IDs of
728     * existing networks. You should assume the network IDs can be different
729     * after calling this method.
730     *
731     * @return {@code true} if the operation succeeded
732     */
733    public boolean saveConfiguration() {
734        try {
735            return mService.saveConfiguration();
736        } catch (RemoteException e) {
737            return false;
738        }
739    }
740
741    /**
742     * Set the country code.
743     * @param countryCode country code in ISO 3166 format.
744     * @param persist {@code true} if this needs to be remembered
745     *
746     * @hide
747     */
748    public void setCountryCode(String country, boolean persist) {
749        try {
750            mService.setCountryCode(country, persist);
751        } catch (RemoteException e) { }
752    }
753
754    /**
755     * Set the operational frequency band.
756     * @param band  One of
757     *     {@link #WIFI_FREQUENCY_BAND_AUTO},
758     *     {@link #WIFI_FREQUENCY_BAND_5GHZ},
759     *     {@link #WIFI_FREQUENCY_BAND_2GHZ},
760     * @param persist {@code true} if this needs to be remembered
761     * @hide
762     */
763    public void setFrequencyBand(int band, boolean persist) {
764        try {
765            mService.setFrequencyBand(band, persist);
766        } catch (RemoteException e) { }
767    }
768
769    /**
770     * Get the operational frequency band.
771     * @return One of
772     *     {@link #WIFI_FREQUENCY_BAND_AUTO},
773     *     {@link #WIFI_FREQUENCY_BAND_5GHZ},
774     *     {@link #WIFI_FREQUENCY_BAND_2GHZ} or
775     *     {@code -1} on failure.
776     * @hide
777     */
778    public int getFrequencyBand() {
779        try {
780            return mService.getFrequencyBand();
781        } catch (RemoteException e) {
782            return -1;
783        }
784    }
785
786    /**
787     * Check if the chipset supports dual frequency band (2.4 GHz and 5 GHz)
788     * @return {@code true} if supported, {@code false} otherwise.
789     * @hide
790     */
791    public boolean isDualBandSupported() {
792        try {
793            return mService.isDualBandSupported();
794        } catch (RemoteException e) {
795            return false;
796        }
797    }
798
799    /**
800     * Return the DHCP-assigned addresses from the last successful DHCP request,
801     * if any.
802     * @return the DHCP information
803     */
804    public DhcpInfo getDhcpInfo() {
805        try {
806            return mService.getDhcpInfo();
807        } catch (RemoteException e) {
808            return null;
809        }
810    }
811
812
813    /**
814     * Enable or disable Wi-Fi.
815     * @param enabled {@code true} to enable, {@code false} to disable.
816     * @return {@code true} if the operation succeeds (or if the existing state
817     *         is the same as the requested state).
818     */
819    public boolean setWifiEnabled(boolean enabled) {
820        try {
821            return mService.setWifiEnabled(enabled);
822        } catch (RemoteException e) {
823            return false;
824        }
825    }
826
827    /**
828     * Gets the Wi-Fi enabled state.
829     * @return One of {@link #WIFI_STATE_DISABLED},
830     *         {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED},
831     *         {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN}
832     * @see #isWifiEnabled()
833     */
834    public int getWifiState() {
835        try {
836            return mService.getWifiEnabledState();
837        } catch (RemoteException e) {
838            return WIFI_STATE_UNKNOWN;
839        }
840    }
841
842    /**
843     * Return whether Wi-Fi is enabled or disabled.
844     * @return {@code true} if Wi-Fi is enabled
845     * @see #getWifiState()
846     */
847    public boolean isWifiEnabled() {
848        return getWifiState() == WIFI_STATE_ENABLED;
849    }
850
851    /**
852     * Calculates the level of the signal. This should be used any time a signal
853     * is being shown.
854     *
855     * @param rssi The power of the signal measured in RSSI.
856     * @param numLevels The number of levels to consider in the calculated
857     *            level.
858     * @return A level of the signal, given in the range of 0 to numLevels-1
859     *         (both inclusive).
860     */
861    public static int calculateSignalLevel(int rssi, int numLevels) {
862        if (rssi <= MIN_RSSI) {
863            return 0;
864        } else if (rssi >= MAX_RSSI) {
865            return numLevels - 1;
866        } else {
867            float inputRange = (MAX_RSSI - MIN_RSSI);
868            float outputRange = (numLevels - 1);
869            return (int)((float)(rssi - MIN_RSSI) * outputRange / inputRange);
870        }
871    }
872
873    /**
874     * Compares two signal strengths.
875     *
876     * @param rssiA The power of the first signal measured in RSSI.
877     * @param rssiB The power of the second signal measured in RSSI.
878     * @return Returns <0 if the first signal is weaker than the second signal,
879     *         0 if the two signals have the same strength, and >0 if the first
880     *         signal is stronger than the second signal.
881     */
882    public static int compareSignalLevel(int rssiA, int rssiB) {
883        return rssiA - rssiB;
884    }
885
886    /**
887     * Start AccessPoint mode with the specified
888     * configuration. If the radio is already running in
889     * AP mode, update the new configuration
890     * Note that starting in access point mode disables station
891     * mode operation
892     * @param wifiConfig SSID, security and channel details as
893     *        part of WifiConfiguration
894     * @return {@code true} if the operation succeeds, {@code false} otherwise
895     *
896     * @hide Dont open up yet
897     */
898    public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
899        try {
900            mService.setWifiApEnabled(wifiConfig, enabled);
901            return true;
902        } catch (RemoteException e) {
903            return false;
904        }
905    }
906
907    /**
908     * Gets the Wi-Fi enabled state.
909     * @return One of {@link #WIFI_AP_STATE_DISABLED},
910     *         {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
911     *         {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
912     * @see #isWifiApEnabled()
913     *
914     * @hide Dont open yet
915     */
916    public int getWifiApState() {
917        try {
918            return mService.getWifiApEnabledState();
919        } catch (RemoteException e) {
920            return WIFI_AP_STATE_FAILED;
921        }
922    }
923
924    /**
925     * Return whether Wi-Fi AP is enabled or disabled.
926     * @return {@code true} if Wi-Fi AP is enabled
927     * @see #getWifiApState()
928     *
929     * @hide Dont open yet
930     */
931    public boolean isWifiApEnabled() {
932        return getWifiApState() == WIFI_AP_STATE_ENABLED;
933    }
934
935    /**
936     * Gets the Wi-Fi AP Configuration.
937     * @return AP details in WifiConfiguration
938     *
939     * @hide Dont open yet
940     */
941    public WifiConfiguration getWifiApConfiguration() {
942        try {
943            return mService.getWifiApConfiguration();
944        } catch (RemoteException e) {
945            return null;
946        }
947    }
948
949    /**
950     * Sets the Wi-Fi AP Configuration.
951     * @return {@code true} if the operation succeeded, {@code false} otherwise
952     *
953     * @hide Dont open yet
954     */
955    public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
956        try {
957            mService.setWifiApConfiguration(wifiConfig);
958            return true;
959        } catch (RemoteException e) {
960            return false;
961        }
962    }
963
964   /**
965     * Start the driver and connect to network.
966     *
967     * This function will over-ride WifiLock and device idle status. For example,
968     * even if the device is idle or there is only a scan-only lock held,
969     * a start wifi would mean that wifi connection is kept active until
970     * a stopWifi() is sent.
971     *
972     * This API is used by WifiStateTracker
973     *
974     * @return {@code true} if the operation succeeds else {@code false}
975     * @hide
976     */
977    public boolean startWifi() {
978        try {
979            mService.startWifi();
980            return true;
981        } catch (RemoteException e) {
982            return false;
983        }
984    }
985
986    /**
987     * Disconnect from a network (if any) and stop the driver.
988     *
989     * This function will over-ride WifiLock and device idle status. Wi-Fi
990     * stays inactive until a startWifi() is issued.
991     *
992     * This API is used by WifiStateTracker
993     *
994     * @return {@code true} if the operation succeeds else {@code false}
995     * @hide
996     */
997    public boolean stopWifi() {
998        try {
999            mService.stopWifi();
1000            return true;
1001        } catch (RemoteException e) {
1002            return false;
1003        }
1004    }
1005
1006    /**
1007     * Add a bssid to the supplicant blacklist
1008     *
1009     * This API is used by WifiWatchdogService
1010     *
1011     * @return {@code true} if the operation succeeds else {@code false}
1012     * @hide
1013     */
1014    public boolean addToBlacklist(String bssid) {
1015        try {
1016            mService.addToBlacklist(bssid);
1017            return true;
1018        } catch (RemoteException e) {
1019            return false;
1020        }
1021    }
1022
1023    /**
1024     * Clear the supplicant blacklist
1025     *
1026     * This API is used by WifiWatchdogService
1027     *
1028     * @return {@code true} if the operation succeeds else {@code false}
1029     * @hide
1030     */
1031    public boolean clearBlacklist() {
1032        try {
1033            mService.clearBlacklist();
1034            return true;
1035        } catch (RemoteException e) {
1036            return false;
1037        }
1038    }
1039
1040    /* TODO: deprecate synchronous API and open up the following API */
1041
1042    private static final int BASE = Protocol.BASE_WIFI_MANAGER;
1043
1044    /* Commands to WifiService */
1045    /** @hide */
1046    public static final int CONNECT_NETWORK                 = BASE + 1;
1047    /** @hide */
1048    public static final int CONNECT_NETWORK_FAILED          = BASE + 2;
1049    /** @hide */
1050    public static final int CONNECT_NETWORK_SUCCEEDED       = BASE + 3;
1051
1052    /** @hide */
1053    public static final int FORGET_NETWORK                  = BASE + 4;
1054    /** @hide */
1055    public static final int FORGET_NETWORK_FAILED           = BASE + 5;
1056    /** @hide */
1057    public static final int FORGET_NETWORK_SUCCEEDED        = BASE + 6;
1058
1059    /** @hide */
1060    public static final int SAVE_NETWORK                    = BASE + 7;
1061    /** @hide */
1062    public static final int SAVE_NETWORK_FAILED             = BASE + 8;
1063    /** @hide */
1064    public static final int SAVE_NETWORK_SUCCEEDED          = BASE + 9;
1065
1066    /** @hide */
1067    public static final int START_WPS                       = BASE + 10;
1068    /** @hide */
1069    public static final int START_WPS_SUCCEEDED             = BASE + 11;
1070    /** @hide */
1071    public static final int WPS_FAILED                      = BASE + 12;
1072   /** @hide */
1073    public static final int WPS_COMPLETED                   = BASE + 13;
1074
1075    /** @hide */
1076    public static final int DISABLE_NETWORK                 = BASE + 14;
1077    /** @hide */
1078    public static final int DISABLE_NETWORK_FAILED          = BASE + 15;
1079    /** @hide */
1080    public static final int DISABLE_NETWORK_SUCCEEDED       = BASE + 16;
1081
1082    /* For system use only */
1083    /** @hide */
1084    public static final int ENABLE_TRAFFIC_STATS_POLL       = BASE + 21;
1085    /** @hide */
1086    public static final int TRAFFIC_STATS_POLL              = BASE + 22;
1087
1088
1089    /**
1090     * Passed with {@link ActionListener#onFailure}.
1091     * Indicates that the operation failed due to an internal error.
1092     * @hide
1093     */
1094    public static final int ERROR               = 0;
1095
1096    /**
1097     * Passed with {@link ActionListener#onFailure}.
1098     * Indicates that the operation is already in progress
1099     * @hide
1100     */
1101    public static final int IN_PROGRESS         = 1;
1102
1103    /**
1104     * Passed with {@link ActionListener#onFailure}.
1105     * Indicates that the operation failed because the framework is busy and
1106     * unable to service the request
1107     * @hide
1108     */
1109    public static final int BUSY                = 2;
1110
1111    /* WPS specific errors */
1112    /** WPS overlap detected {@hide} */
1113    public static final int WPS_OVERLAP_ERROR   = 3;
1114
1115    /** Interface for callback invocation when framework channel is lost {@hide} */
1116    public interface ChannelListener {
1117        /**
1118         * The channel to the framework has been disconnected.
1119         * Application could try re-initializing using {@link #initialize}
1120         */
1121        public void onChannelDisconnected();
1122    }
1123
1124    /** Interface for callback invocation on an application action {@hide} */
1125    public interface ActionListener {
1126        /** The operation succeeded */
1127        public void onSuccess();
1128        /**
1129         * The operation failed
1130         * @param reason The reason for failure could be one of
1131         * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY}
1132         */
1133        public void onFailure(int reason);
1134    }
1135
1136    /** Interface for callback invocation on a start WPS action {@hide} */
1137    public interface WpsListener {
1138        /** WPS start succeeded */
1139        public void onStartSuccess(String pin);
1140
1141        /** WPS operation completed succesfully */
1142        public void onCompletion();
1143
1144        /**
1145         * WPS operation failed
1146         * @param reason The reason for failure could be one of
1147         * {@link #IN_PROGRESS}, {@link #WPS_OVERLAP_ERROR},{@link #ERROR} or {@link #BUSY}
1148         */
1149        public void onFailure(int reason);
1150    }
1151
1152    /**
1153     * A channel that connects the application to the Wifi framework.
1154     * Most operations require a Channel as an argument. An instance of Channel is obtained
1155     * by doing a call on {@link #initialize}
1156     * @hide
1157     */
1158    public static class Channel {
1159        Channel(Looper looper, ChannelListener l) {
1160            mAsyncChannel = new AsyncChannel();
1161            mHandler = new WifiHandler(looper);
1162            mChannelListener = l;
1163        }
1164        private ChannelListener mChannelListener;
1165        private SparseArray<Object> mListenerMap = new SparseArray<Object>();
1166        private Object mListenerMapLock = new Object();
1167        private int mListenerKey = 0;
1168
1169        AsyncChannel mAsyncChannel;
1170        WifiHandler mHandler;
1171        class WifiHandler extends Handler {
1172            WifiHandler(Looper looper) {
1173                super(looper);
1174            }
1175
1176            @Override
1177            public void handleMessage(Message message) {
1178                Object listener = removeListener(message.arg2);
1179                switch (message.what) {
1180                    case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
1181                        if (mChannelListener != null) {
1182                            mChannelListener.onChannelDisconnected();
1183                            mChannelListener = null;
1184                        }
1185                        break;
1186                        /* ActionListeners grouped together */
1187                    case WifiManager.CONNECT_NETWORK_FAILED:
1188                    case WifiManager.FORGET_NETWORK_FAILED:
1189                    case WifiManager.SAVE_NETWORK_FAILED:
1190                    case WifiManager.DISABLE_NETWORK_FAILED:
1191                        if (listener != null) {
1192                            ((ActionListener) listener).onFailure(message.arg1);
1193                        }
1194                        break;
1195                        /* ActionListeners grouped together */
1196                    case WifiManager.CONNECT_NETWORK_SUCCEEDED:
1197                    case WifiManager.FORGET_NETWORK_SUCCEEDED:
1198                    case WifiManager.SAVE_NETWORK_SUCCEEDED:
1199                    case WifiManager.DISABLE_NETWORK_SUCCEEDED:
1200                        if (listener != null) {
1201                            ((ActionListener) listener).onSuccess();
1202                        }
1203                        break;
1204                    case WifiManager.START_WPS_SUCCEEDED:
1205                        if (listener != null) {
1206                            WpsResult result = (WpsResult) message.obj;
1207                            ((WpsListener) listener).onStartSuccess(result.pin);
1208                            //Listener needs to stay until completion or failure
1209                            synchronized(mListenerMapLock) {
1210                                mListenerMap.put(message.arg2, listener);
1211                            }
1212                        }
1213                        break;
1214                    case WifiManager.WPS_COMPLETED:
1215                        if (listener != null) {
1216                            ((WpsListener) listener).onCompletion();
1217                        }
1218                        break;
1219                    case WifiManager.WPS_FAILED:
1220                        if (listener != null) {
1221                            ((WpsListener) listener).onFailure(message.arg1);
1222                        }
1223                        break;
1224                    default:
1225                        //ignore
1226                        break;
1227                }
1228            }
1229        }
1230
1231        int putListener(Object listener) {
1232            if (listener == null) return 0;
1233            int key;
1234            synchronized (mListenerMapLock) {
1235                key = mListenerKey++;
1236                mListenerMap.put(key, listener);
1237            }
1238            return key;
1239        }
1240
1241        Object removeListener(int key) {
1242            synchronized (mListenerMapLock) {
1243                Object listener = mListenerMap.get(key);
1244                mListenerMap.remove(key);
1245                return listener;
1246            }
1247        }
1248    }
1249
1250    /**
1251     * Registers the application with the Wi-Fi framework. This function
1252     * must be the first to be called before any Wi-Fi operations are performed.
1253     *
1254     * @param srcContext is the context of the source
1255     * @param srcLooper is the Looper on which the callbacks are receivied
1256     * @param listener for callback at loss of framework communication. Can be null.
1257     * @return Channel instance that is necessary for performing any further Wi-Fi operations.
1258     *         A null is returned upon failure to initialize.
1259     * @hide
1260     */
1261    public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
1262        Messenger messenger = getWifiServiceMessenger();
1263        if (messenger == null) return null;
1264
1265        Channel c = new Channel(srcLooper, listener);
1266        if (c.mAsyncChannel.connectSync(srcContext, c.mHandler, messenger)
1267                == AsyncChannel.STATUS_SUCCESSFUL) {
1268            return c;
1269        } else {
1270            return null;
1271        }
1272    }
1273
1274    /**
1275     * Connect to a network with the given configuration. The network also
1276     * gets added to the supplicant configuration.
1277     *
1278     * For a new network, this function is used instead of a
1279     * sequence of addNetwork(), enableNetwork(), saveConfiguration() and
1280     * reconnect()
1281     *
1282     * @param c is the channel created at {@link #initialize}
1283     * @param config the set of variables that describe the configuration,
1284     *            contained in a {@link WifiConfiguration} object.
1285     * @param listener for callbacks on success or failure. Can be null.
1286     * @hide
1287     */
1288    public void connect(Channel c, WifiConfiguration config, ActionListener listener) {
1289        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
1290        if (config == null) throw new IllegalArgumentException("config cannot be null");
1291
1292        c.mAsyncChannel.sendMessage(CONNECT_NETWORK, 0, c.putListener(listener), config);
1293    }
1294
1295    /**
1296     * Connect to a network with the given networkId.
1297     *
1298     * This function is used instead of a enableNetwork(), saveConfiguration() and
1299     * reconnect()
1300     *
1301     * @param c is the channel created at {@link #initialize}
1302     * @param networkId the network id identifiying the network in the
1303     *                supplicant configuration list
1304     * @param listener for callbacks on success or failure. Can be null.
1305     * @hide
1306     */
1307    public void connect(Channel c, int networkId, ActionListener listener) {
1308        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
1309        if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
1310
1311        c.mAsyncChannel.sendMessage(CONNECT_NETWORK, networkId, c.putListener(listener));
1312    }
1313
1314    /**
1315     * Save the given network in the supplicant config. If the network already
1316     * exists, the configuration is updated. A new network is enabled
1317     * by default.
1318     *
1319     * For a new network, this function is used instead of a
1320     * sequence of addNetwork(), enableNetwork() and saveConfiguration().
1321     *
1322     * For an existing network, it accomplishes the task of updateNetwork()
1323     * and saveConfiguration()
1324     *
1325     * @param c is the channel created at {@link #initialize}
1326     * @param config the set of variables that describe the configuration,
1327     *            contained in a {@link WifiConfiguration} object.
1328     * @param listener for callbacks on success or failure. Can be null.
1329     * @hide
1330     */
1331    public void save(Channel c, WifiConfiguration config, ActionListener listener) {
1332        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
1333        if (config == null) throw new IllegalArgumentException("config cannot be null");
1334
1335        c.mAsyncChannel.sendMessage(SAVE_NETWORK, 0, c.putListener(listener), config);
1336    }
1337
1338    /**
1339     * Delete the network in the supplicant config.
1340     *
1341     * This function is used instead of a sequence of removeNetwork()
1342     * and saveConfiguration().
1343     *
1344     * @param c is the channel created at {@link #initialize}
1345     * @param config the set of variables that describe the configuration,
1346     *            contained in a {@link WifiConfiguration} object.
1347     * @param listener for callbacks on success or failure. Can be null.
1348     * @hide
1349     */
1350    public void forget(Channel c, int netId, ActionListener listener) {
1351        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
1352        if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
1353
1354        c.mAsyncChannel.sendMessage(FORGET_NETWORK, netId, c.putListener(listener));
1355    }
1356
1357    /**
1358     * Disable network
1359     *
1360     * @param c is the channel created at {@link #initialize}
1361     * @param netId is the network Id
1362     * @param listener for callbacks on success or failure. Can be null.
1363     * @hide
1364     */
1365    public void disable(Channel c, int netId, ActionListener listener) {
1366        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
1367        if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
1368
1369        c.mAsyncChannel.sendMessage(DISABLE_NETWORK, netId, c.putListener(listener));
1370    }
1371
1372    /**
1373     * Start Wi-fi Protected Setup
1374     *
1375     * @param c is the channel created at {@link #initialize}
1376     * @param config WPS configuration
1377     * @param listener for callbacks on success or failure. Can be null.
1378     * @hide
1379     */
1380    public void startWps(Channel c, WpsInfo config, WpsListener listener) {
1381        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
1382        if (config == null) throw new IllegalArgumentException("config cannot be null");
1383
1384        c.mAsyncChannel.sendMessage(START_WPS, 0, c.putListener(listener), config);
1385    }
1386
1387    /**
1388     * Get a reference to WifiService handler. This is used by a client to establish
1389     * an AsyncChannel communication with WifiService
1390     *
1391     * @return Messenger pointing to the WifiService handler
1392     * @hide
1393     */
1394    public Messenger getWifiServiceMessenger() {
1395        try {
1396            return mService.getWifiServiceMessenger();
1397        } catch (RemoteException e) {
1398            return null;
1399        }
1400    }
1401
1402    /**
1403     * Get a reference to WifiStateMachine handler.
1404     * @return Messenger pointing to the WifiService handler
1405     * @hide
1406     */
1407    public Messenger getWifiStateMachineMessenger() {
1408        try {
1409            return mService.getWifiStateMachineMessenger();
1410        } catch (RemoteException e) {
1411            return null;
1412        }
1413    }
1414
1415
1416
1417    /**
1418     * Returns the file in which IP and proxy configuration data is stored
1419     * @hide
1420     */
1421    public String getConfigFile() {
1422        try {
1423            return mService.getConfigFile();
1424        } catch (RemoteException e) {
1425            return null;
1426        }
1427    }
1428
1429    /**
1430     * Allows an application to keep the Wi-Fi radio awake.
1431     * Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
1432     * Acquiring a WifiLock will keep the radio on until the lock is released.  Multiple
1433     * applications may hold WifiLocks, and the radio will only be allowed to turn off when no
1434     * WifiLocks are held in any application.
1435     * <p>
1436     * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or
1437     * could function over a mobile network, if available.  A program that needs to download large
1438     * files should hold a WifiLock to ensure that the download will complete, but a program whose
1439     * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely
1440     * affecting battery life.
1441     * <p>
1442     * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane
1443     * Mode.  They simply keep the radio from turning off when Wi-Fi is already on but the device
1444     * is idle.
1445     * <p>
1446     * Any application using a WifiLock must request the {@code android.permission.WAKE_LOCK}
1447     * permission in an {@code &lt;uses-permission&gt;} element of the application's manifest.
1448     */
1449    public class WifiLock {
1450        private String mTag;
1451        private final IBinder mBinder;
1452        private int mRefCount;
1453        int mLockType;
1454        private boolean mRefCounted;
1455        private boolean mHeld;
1456        private WorkSource mWorkSource;
1457
1458        private WifiLock(int lockType, String tag) {
1459            mTag = tag;
1460            mLockType = lockType;
1461            mBinder = new Binder();
1462            mRefCount = 0;
1463            mRefCounted = true;
1464            mHeld = false;
1465        }
1466
1467        /**
1468         * Locks the Wi-Fi radio on until {@link #release} is called.
1469         *
1470         * If this WifiLock is reference-counted, each call to {@code acquire} will increment the
1471         * reference count, and the radio will remain locked as long as the reference count is
1472         * above zero.
1473         *
1474         * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock
1475         * the radio, but subsequent calls will be ignored.  Only one call to {@link #release}
1476         * will be required, regardless of the number of times that {@code acquire} is called.
1477         */
1478        public void acquire() {
1479            synchronized (mBinder) {
1480                if (mRefCounted ? (++mRefCount > 0) : (!mHeld)) {
1481                    try {
1482                        mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource);
1483                        synchronized (WifiManager.this) {
1484                            if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
1485                                mService.releaseWifiLock(mBinder);
1486                                throw new UnsupportedOperationException(
1487                                            "Exceeded maximum number of wifi locks");
1488                            }
1489                            mActiveLockCount++;
1490                        }
1491                    } catch (RemoteException ignore) {
1492                    }
1493                    mHeld = true;
1494                }
1495            }
1496        }
1497
1498        /**
1499         * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle.
1500         *
1501         * If this WifiLock is reference-counted, each call to {@code release} will decrement the
1502         * reference count, and the radio will be unlocked only when the reference count reaches
1503         * zero.  If the reference count goes below zero (that is, if {@code release} is called
1504         * a greater number of times than {@link #acquire}), an exception is thrown.
1505         *
1506         * If this WifiLock is not reference-counted, the first call to {@code release} (after
1507         * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent
1508         * calls will be ignored.
1509         */
1510        public void release() {
1511            synchronized (mBinder) {
1512                if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
1513                    try {
1514                        mService.releaseWifiLock(mBinder);
1515                        synchronized (WifiManager.this) {
1516                            mActiveLockCount--;
1517                        }
1518                    } catch (RemoteException ignore) {
1519                    }
1520                    mHeld = false;
1521                }
1522                if (mRefCount < 0) {
1523                    throw new RuntimeException("WifiLock under-locked " + mTag);
1524                }
1525            }
1526        }
1527
1528        /**
1529         * Controls whether this is a reference-counted or non-reference-counted WifiLock.
1530         *
1531         * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and
1532         * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire}
1533         * has been balanced with a call to {@link #release}.  Non-reference-counted WifiLocks
1534         * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the
1535         * radio whenever {@link #release} is called and it is locked.
1536         *
1537         * @param refCounted true if this WifiLock should keep a reference count
1538         */
1539        public void setReferenceCounted(boolean refCounted) {
1540            mRefCounted = refCounted;
1541        }
1542
1543        /**
1544         * Checks whether this WifiLock is currently held.
1545         *
1546         * @return true if this WifiLock is held, false otherwise
1547         */
1548        public boolean isHeld() {
1549            synchronized (mBinder) {
1550                return mHeld;
1551            }
1552        }
1553
1554        public void setWorkSource(WorkSource ws) {
1555            synchronized (mBinder) {
1556                if (ws != null && ws.size() == 0) {
1557                    ws = null;
1558                }
1559                boolean changed = true;
1560                if (ws == null) {
1561                    mWorkSource = null;
1562                } else if (mWorkSource == null) {
1563                    changed = mWorkSource != null;
1564                    mWorkSource = new WorkSource(ws);
1565                } else {
1566                    changed = mWorkSource.diff(ws);
1567                    if (changed) {
1568                        mWorkSource.set(ws);
1569                    }
1570                }
1571                if (changed && mHeld) {
1572                    try {
1573                        mService.updateWifiLockWorkSource(mBinder, mWorkSource);
1574                    } catch (RemoteException e) {
1575                    }
1576                }
1577            }
1578        }
1579
1580        public String toString() {
1581            String s1, s2, s3;
1582            synchronized (mBinder) {
1583                s1 = Integer.toHexString(System.identityHashCode(this));
1584                s2 = mHeld ? "held; " : "";
1585                if (mRefCounted) {
1586                    s3 = "refcounted: refcount = " + mRefCount;
1587                } else {
1588                    s3 = "not refcounted";
1589                }
1590                return "WifiLock{ " + s1 + "; " + s2 + s3 + " }";
1591            }
1592        }
1593
1594        @Override
1595        protected void finalize() throws Throwable {
1596            super.finalize();
1597            synchronized (mBinder) {
1598                if (mHeld) {
1599                    try {
1600                        mService.releaseWifiLock(mBinder);
1601                        synchronized (WifiManager.this) {
1602                            mActiveLockCount--;
1603                        }
1604                    } catch (RemoteException ignore) {
1605                    }
1606                }
1607            }
1608        }
1609    }
1610
1611    /**
1612     * Creates a new WifiLock.
1613     *
1614     * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL},
1615     * {@link #WIFI_MODE_FULL_HIGH_PERF} and {@link #WIFI_MODE_SCAN_ONLY} for
1616     * descriptions of the types of Wi-Fi locks.
1617     * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
1618     *            never shown to the user under normal conditions, but should be descriptive
1619     *            enough to identify your application and the specific WifiLock within it, if it
1620     *            holds multiple WifiLocks.
1621     *
1622     * @return a new, unacquired WifiLock with the given tag.
1623     *
1624     * @see WifiLock
1625     */
1626    public WifiLock createWifiLock(int lockType, String tag) {
1627        return new WifiLock(lockType, tag);
1628    }
1629
1630    /**
1631     * Creates a new WifiLock.
1632     *
1633     * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
1634     *            never shown to the user under normal conditions, but should be descriptive
1635     *            enough to identify your application and the specific WifiLock within it, if it
1636     *            holds multiple WifiLocks.
1637     *
1638     * @return a new, unacquired WifiLock with the given tag.
1639     *
1640     * @see WifiLock
1641     */
1642    public WifiLock createWifiLock(String tag) {
1643        return new WifiLock(WIFI_MODE_FULL, tag);
1644    }
1645
1646
1647    /**
1648     * Create a new MulticastLock
1649     *
1650     * @param tag a tag for the MulticastLock to identify it in debugging
1651     *            messages.  This string is never shown to the user under
1652     *            normal conditions, but should be descriptive enough to
1653     *            identify your application and the specific MulticastLock
1654     *            within it, if it holds multiple MulticastLocks.
1655     *
1656     * @return a new, unacquired MulticastLock with the given tag.
1657     *
1658     * @see MulticastLock
1659     */
1660    public MulticastLock createMulticastLock(String tag) {
1661        return new MulticastLock(tag);
1662    }
1663
1664    /**
1665     * Allows an application to receive Wifi Multicast packets.
1666     * Normally the Wifi stack filters out packets not explicitly
1667     * addressed to this device.  Acquring a MulticastLock will
1668     * cause the stack to receive packets addressed to multicast
1669     * addresses.  Processing these extra packets can cause a noticable
1670     * battery drain and should be disabled when not needed.
1671     */
1672    public class MulticastLock {
1673        private String mTag;
1674        private final IBinder mBinder;
1675        private int mRefCount;
1676        private boolean mRefCounted;
1677        private boolean mHeld;
1678
1679        private MulticastLock(String tag) {
1680            mTag = tag;
1681            mBinder = new Binder();
1682            mRefCount = 0;
1683            mRefCounted = true;
1684            mHeld = false;
1685        }
1686
1687        /**
1688         * Locks Wifi Multicast on until {@link #release} is called.
1689         *
1690         * If this MulticastLock is reference-counted each call to
1691         * {@code acquire} will increment the reference count, and the
1692         * wifi interface will receive multicast packets as long as the
1693         * reference count is above zero.
1694         *
1695         * If this MulticastLock is not reference-counted, the first call to
1696         * {@code acquire} will turn on the multicast packets, but subsequent
1697         * calls will be ignored.  Only one call to {@link #release} will
1698         * be required, regardless of the number of times that {@code acquire}
1699         * is called.
1700         *
1701         * Note that other applications may also lock Wifi Multicast on.
1702         * Only they can relinquish their lock.
1703         *
1704         * Also note that applications cannot leave Multicast locked on.
1705         * When an app exits or crashes, any Multicast locks will be released.
1706         */
1707        public void acquire() {
1708            synchronized (mBinder) {
1709                if (mRefCounted ? (++mRefCount > 0) : (!mHeld)) {
1710                    try {
1711                        mService.acquireMulticastLock(mBinder, mTag);
1712                        synchronized (WifiManager.this) {
1713                            if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
1714                                mService.releaseMulticastLock();
1715                                throw new UnsupportedOperationException(
1716                                        "Exceeded maximum number of wifi locks");
1717                            }
1718                            mActiveLockCount++;
1719                        }
1720                    } catch (RemoteException ignore) {
1721                    }
1722                    mHeld = true;
1723                }
1724            }
1725        }
1726
1727        /**
1728         * Unlocks Wifi Multicast, restoring the filter of packets
1729         * not addressed specifically to this device and saving power.
1730         *
1731         * If this MulticastLock is reference-counted, each call to
1732         * {@code release} will decrement the reference count, and the
1733         * multicast packets will only stop being received when the reference
1734         * count reaches zero.  If the reference count goes below zero (that
1735         * is, if {@code release} is called a greater number of times than
1736         * {@link #acquire}), an exception is thrown.
1737         *
1738         * If this MulticastLock is not reference-counted, the first call to
1739         * {@code release} (after the radio was multicast locked using
1740         * {@link #acquire}) will unlock the multicast, and subsequent calls
1741         * will be ignored.
1742         *
1743         * Note that if any other Wifi Multicast Locks are still outstanding
1744         * this {@code release} call will not have an immediate effect.  Only
1745         * when all applications have released all their Multicast Locks will
1746         * the Multicast filter be turned back on.
1747         *
1748         * Also note that when an app exits or crashes all of its Multicast
1749         * Locks will be automatically released.
1750         */
1751        public void release() {
1752            synchronized (mBinder) {
1753                if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
1754                    try {
1755                        mService.releaseMulticastLock();
1756                        synchronized (WifiManager.this) {
1757                            mActiveLockCount--;
1758                        }
1759                    } catch (RemoteException ignore) {
1760                    }
1761                    mHeld = false;
1762                }
1763                if (mRefCount < 0) {
1764                    throw new RuntimeException("MulticastLock under-locked "
1765                            + mTag);
1766                }
1767            }
1768        }
1769
1770        /**
1771         * Controls whether this is a reference-counted or non-reference-
1772         * counted MulticastLock.
1773         *
1774         * Reference-counted MulticastLocks keep track of the number of calls
1775         * to {@link #acquire} and {@link #release}, and only stop the
1776         * reception of multicast packets when every call to {@link #acquire}
1777         * has been balanced with a call to {@link #release}.  Non-reference-
1778         * counted MulticastLocks allow the reception of multicast packets
1779         * whenever {@link #acquire} is called and stop accepting multicast
1780         * packets whenever {@link #release} is called.
1781         *
1782         * @param refCounted true if this MulticastLock should keep a reference
1783         * count
1784         */
1785        public void setReferenceCounted(boolean refCounted) {
1786            mRefCounted = refCounted;
1787        }
1788
1789        /**
1790         * Checks whether this MulticastLock is currently held.
1791         *
1792         * @return true if this MulticastLock is held, false otherwise
1793         */
1794        public boolean isHeld() {
1795            synchronized (mBinder) {
1796                return mHeld;
1797            }
1798        }
1799
1800        public String toString() {
1801            String s1, s2, s3;
1802            synchronized (mBinder) {
1803                s1 = Integer.toHexString(System.identityHashCode(this));
1804                s2 = mHeld ? "held; " : "";
1805                if (mRefCounted) {
1806                    s3 = "refcounted: refcount = " + mRefCount;
1807                } else {
1808                    s3 = "not refcounted";
1809                }
1810                return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }";
1811            }
1812        }
1813
1814        @Override
1815        protected void finalize() throws Throwable {
1816            super.finalize();
1817            setReferenceCounted(false);
1818            release();
1819        }
1820    }
1821
1822    /**
1823     * Check multicast filter status.
1824     *
1825     * @return true if multicast packets are allowed.
1826     *
1827     * @hide pending API council approval
1828     */
1829    public boolean isMulticastEnabled() {
1830        try {
1831            return mService.isMulticastEnabled();
1832        } catch (RemoteException e) {
1833            return false;
1834        }
1835    }
1836
1837    /**
1838     * Initialize the multicast filtering to 'on'
1839     * @hide no intent to publish
1840     */
1841    public boolean initializeMulticastFiltering() {
1842        try {
1843            mService.initializeMulticastFiltering();
1844            return true;
1845        } catch (RemoteException e) {
1846             return false;
1847        }
1848    }
1849}
1850