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