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