WifiManager.java revision 36f7413dabfab50699135019ba55151e9227f59d
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    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
135    public static final String WIFI_AP_STATE_CHANGED_ACTION =
136        "android.net.wifi.WIFI_AP_STATE_CHANGED";
137
138    /**
139     * The lookup key for an int that indicates whether Wi-Fi AP is enabled,
140     * disabled, enabling, disabling, or failed.  Retrieve it with
141     * {@link android.content.Intent#getIntExtra(String,int)}.
142     *
143     * @see #WIFI_AP_STATE_DISABLED
144     * @see #WIFI_AP_STATE_DISABLING
145     * @see #WIFI_AP_STATE_ENABLED
146     * @see #WIFI_AP_STATE_ENABLING
147     * @see #WIFI_AP_STATE_FAILED
148     *
149     * @hide
150     */
151    public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
152    /**
153     * The previous Wi-Fi state.
154     *
155     * @see #EXTRA_WIFI_AP_STATE
156     *
157     * @hide
158     */
159    public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
160    /**
161     * Wi-Fi AP is currently being disabled. The state will change to
162     * {@link #WIFI_AP_STATE_DISABLED} if it finishes successfully.
163     *
164     * @see #WIFI_AP_STATE_CHANGED_ACTION
165     * @see #getWifiApState()
166     *
167     * @hide
168     */
169    public static final int WIFI_AP_STATE_DISABLING = 10;
170    /**
171     * Wi-Fi AP is disabled.
172     *
173     * @see #WIFI_AP_STATE_CHANGED_ACTION
174     * @see #getWifiState()
175     *
176     * @hide
177     */
178    public static final int WIFI_AP_STATE_DISABLED = 11;
179    /**
180     * Wi-Fi AP is currently being enabled. The state will change to
181     * {@link #WIFI_AP_STATE_ENABLED} if it finishes successfully.
182     *
183     * @see #WIFI_AP_STATE_CHANGED_ACTION
184     * @see #getWifiApState()
185     *
186     * @hide
187     */
188    public static final int WIFI_AP_STATE_ENABLING = 12;
189    /**
190     * Wi-Fi AP is enabled.
191     *
192     * @see #WIFI_AP_STATE_CHANGED_ACTION
193     * @see #getWifiApState()
194     *
195     * @hide
196     */
197    public static final int WIFI_AP_STATE_ENABLED = 13;
198    /**
199     * Wi-Fi AP is in a failed state. This state will occur when an error occurs during
200     * enabling or disabling
201     *
202     * @see #WIFI_AP_STATE_CHANGED_ACTION
203     * @see #getWifiApState()
204     *
205     * @hide
206     */
207    public static final int WIFI_AP_STATE_FAILED = 14;
208
209    /**
210     * Broadcast intent action indicating that a connection to the supplicant has
211     * been established (and it is now possible
212     * to perform Wi-Fi operations) or the connection to the supplicant has been
213     * lost. One extra provides the connection state as a boolean, where {@code true}
214     * means CONNECTED.
215     * @see #EXTRA_SUPPLICANT_CONNECTED
216     */
217    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
218    public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION =
219        "android.net.wifi.supplicant.CONNECTION_CHANGE";
220    /**
221     * The lookup key for a boolean that indicates whether a connection to
222     * the supplicant daemon has been gained or lost. {@code true} means
223     * a connection now exists.
224     * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
225     */
226    public static final String EXTRA_SUPPLICANT_CONNECTED = "connected";
227    /**
228     * Broadcast intent action indicating that the state of Wi-Fi connectivity
229     * has changed. One extra provides the new state
230     * in the form of a {@link android.net.NetworkInfo} object. If the new state is
231     * CONNECTED, a second extra may provide the BSSID of the access point,
232     * as a {@code String}.
233     * @see #EXTRA_NETWORK_INFO
234     * @see #EXTRA_BSSID
235     */
236    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
237    public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
238    /**
239     * The lookup key for a {@link android.net.NetworkInfo} object associated with the
240     * Wi-Fi network. Retrieve with
241     * {@link android.content.Intent#getParcelableExtra(String)}.
242     */
243    public static final String EXTRA_NETWORK_INFO = "networkInfo";
244    /**
245     * The lookup key for a String giving the BSSID of the access point to which
246     * we are connected. Only present when the new state is CONNECTED.
247     * Retrieve with
248     * {@link android.content.Intent#getStringExtra(String)}.
249     */
250    public static final String EXTRA_BSSID = "bssid";
251    /**
252     * Broadcast intent action indicating that the state of establishing a connection to
253     * an access point has changed.One extra provides the new
254     * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and
255     * is not generally the most useful thing to look at if you are just interested in
256     * the overall state of connectivity.
257     * @see #EXTRA_NEW_STATE
258     * @see #EXTRA_SUPPLICANT_ERROR
259     */
260    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
261    public static final String SUPPLICANT_STATE_CHANGED_ACTION =
262        "android.net.wifi.supplicant.STATE_CHANGE";
263    /**
264     * The lookup key for a {@link SupplicantState} describing the new state
265     * Retrieve with
266     * {@link android.content.Intent#getParcelableExtra(String)}.
267     */
268    public static final String EXTRA_NEW_STATE = "newState";
269
270    /**
271     * The lookup key for a {@link SupplicantState} describing the supplicant
272     * error code if any
273     * Retrieve with
274     * {@link android.content.Intent#getIntExtra(String, int)}.
275     * @see #ERROR_AUTHENTICATING
276     */
277    public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError";
278    /**
279     * Broadcast intent action indicating that the supplicant configuration changed.
280     * This can be as a result of adding/updating/deleting a network
281     * @hide
282     */
283    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
284    public static final String SUPPLICANT_CONFIG_CHANGED_ACTION =
285        "android.net.wifi.supplicant.CONFIG_CHANGE";
286    /**
287     * An access point scan has completed, and results are available from the supplicant.
288     * Call {@link #getScanResults()} to obtain the results.
289     */
290    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
291    public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
292    /**
293     * The RSSI (signal strength) has changed.
294     * @see #EXTRA_NEW_RSSI
295     */
296    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
297    public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
298    /**
299     * The lookup key for an {@code int} giving the new RSSI in dBm.
300     */
301    public static final String EXTRA_NEW_RSSI = "newRssi";
302
303    /**
304     * Broadcast intent action indicating that the IP configuration
305     * changed on wifi.
306     * @hide
307     */
308    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
309    public static final String CONFIG_CHANGED_ACTION = "android.net.wifi.CONFIG_CHANGED";
310
311    /**
312     * The lookup key for a {@link android.net.LinkProperties} object associated with the
313     * Wi-Fi network. Retrieve with
314     * {@link android.content.Intent#getParcelableExtra(String)}.
315     * @hide
316     */
317    public static final String EXTRA_LINK_PROPERTIES = "linkProperties";
318
319    /**
320     * The lookup key for a {@link android.net.LinkCapabilities} object associated with the
321     * Wi-Fi network. Retrieve with
322     * {@link android.content.Intent#getParcelableExtra(String)}.
323     * @hide
324     */
325    public static final String EXTRA_LINK_CAPABILITIES = "linkCapabilities";
326
327    /**
328     * The network IDs of the configured networks could have changed.
329     */
330    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
331    public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
332
333    /**
334     * Activity Action: Pick a Wi-Fi network to connect to.
335     * <p>Input: Nothing.
336     * <p>Output: Nothing.
337     */
338    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
339    public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
340
341    /**
342     * In this Wi-Fi lock mode, Wi-Fi will behave as in the mode
343     * {@link #WIFI_MODE_FULL} but it operates at high performance
344     * at the expense of power. This mode should be used
345     * only when the wifi connection needs to have minimum loss and low
346     * latency as it can impact the battery life.
347     * @hide
348     */
349    public static final int WIFI_MODE_FULL_HIGH_PERF = 3;
350
351    /**
352     * In this Wi-Fi lock mode, Wi-Fi will be kept active,
353     * and will behave normally, i.e., it will attempt to automatically
354     * establish a connection to a remembered access point that is
355     * within range, and will do periodic scans if there are remembered
356     * access points but none are in range.
357     */
358    public static final int WIFI_MODE_FULL = 1;
359    /**
360     * In this Wi-Fi lock mode, Wi-Fi will be kept active,
361     * but the only operation that will be supported is initiation of
362     * scans, and the subsequent reporting of scan results. No attempts
363     * will be made to automatically connect to remembered access points,
364     * nor will periodic scans be automatically performed looking for
365     * remembered access points. Scans must be explicitly requested by
366     * an application in this mode.
367     */
368    public static final int WIFI_MODE_SCAN_ONLY = 2;
369
370    /** Anything worse than or equal to this will show 0 bars. */
371    private static final int MIN_RSSI = -100;
372
373    /** Anything better than or equal to this will show the max bars. */
374    private static final int MAX_RSSI = -55;
375
376    /**
377     * Auto settings in the driver. The driver could choose to operate on both
378     * 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band.
379     * @hide
380     */
381    public static final int WIFI_FREQUENCY_BAND_AUTO = 0;
382
383    /**
384     * Operation on 5 GHz alone
385     * @hide
386     */
387    public static final int WIFI_FREQUENCY_BAND_5GHZ = 1;
388
389    /**
390     * Operation on 2.4 GHz alone
391     * @hide
392     */
393    public static final int WIFI_FREQUENCY_BAND_2GHZ = 2;
394
395    IWifiManager mService;
396    Handler mHandler;
397
398    /* Maximum number of active locks we allow.
399     * This limit was added to prevent apps from creating a ridiculous number
400     * of locks and crashing the system by overflowing the global ref table.
401     */
402    private static final int MAX_ACTIVE_LOCKS = 50;
403
404    /* Number of currently active WifiLocks and MulticastLocks */
405    private int mActiveLockCount;
406
407    /**
408     * Create a new WifiManager instance.
409     * Applications will almost always want to use
410     * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
411     * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
412     * @param service the Binder interface
413     * @param handler target for messages
414     * @hide - hide this because it takes in a parameter of type IWifiManager, which
415     * is a system private class.
416     */
417    public WifiManager(IWifiManager service, Handler handler) {
418        mService = service;
419        mHandler = handler;
420    }
421
422    /**
423     * Return a list of all the networks configured in the supplicant.
424     * Not all fields of WifiConfiguration are returned. Only the following
425     * fields are filled in:
426     * <ul>
427     * <li>networkId</li>
428     * <li>SSID</li>
429     * <li>BSSID</li>
430     * <li>priority</li>
431     * <li>allowedProtocols</li>
432     * <li>allowedKeyManagement</li>
433     * <li>allowedAuthAlgorithms</li>
434     * <li>allowedPairwiseCiphers</li>
435     * <li>allowedGroupCiphers</li>
436     * </ul>
437     * @return a list of network configurations in the form of a list
438     * of {@link WifiConfiguration} objects.
439     */
440    public List<WifiConfiguration> getConfiguredNetworks() {
441        try {
442            return mService.getConfiguredNetworks();
443        } catch (RemoteException e) {
444            return null;
445        }
446    }
447
448    /**
449     * Add a new network description to the set of configured networks.
450     * The {@code networkId} field of the supplied configuration object
451     * is ignored.
452     * <p/>
453     * The new network will be marked DISABLED by default. To enable it,
454     * called {@link #enableNetwork}.
455     *
456     * @param config the set of variables that describe the configuration,
457     *            contained in a {@link WifiConfiguration} object.
458     * @return the ID of the newly created network description. This is used in
459     *         other operations to specified the network to be acted upon.
460     *         Returns {@code -1} on failure.
461     */
462    public int addNetwork(WifiConfiguration config) {
463        if (config == null) {
464            return -1;
465        }
466        config.networkId = -1;
467        return addOrUpdateNetwork(config);
468    }
469
470    /**
471     * Update the network description of an existing configured network.
472     *
473     * @param config the set of variables that describe the configuration,
474     *            contained in a {@link WifiConfiguration} object. It may
475     *            be sparse, so that only the items that are being changed
476     *            are non-<code>null</code>. The {@code networkId} field
477     *            must be set to the ID of the existing network being updated.
478     * @return Returns the {@code networkId} of the supplied
479     *         {@code WifiConfiguration} on success.
480     *         <br/>
481     *         Returns {@code -1} on failure, including when the {@code networkId}
482     *         field of the {@code WifiConfiguration} does not refer to an
483     *         existing network.
484     */
485    public int updateNetwork(WifiConfiguration config) {
486        if (config == null || config.networkId < 0) {
487            return -1;
488        }
489        return addOrUpdateNetwork(config);
490    }
491
492    /**
493     * Internal method for doing the RPC that creates a new network description
494     * or updates an existing one.
495     *
496     * @param config The possibly sparse object containing the variables that
497     *         are to set or updated in the network description.
498     * @return the ID of the network on success, {@code -1} on failure.
499     */
500    private int addOrUpdateNetwork(WifiConfiguration config) {
501        try {
502            return mService.addOrUpdateNetwork(config);
503        } catch (RemoteException e) {
504            return -1;
505        }
506    }
507
508    /**
509     * Remove the specified network from the list of configured networks.
510     * This may result in the asynchronous delivery of state change
511     * events.
512     * @param netId the integer that identifies the network configuration
513     * to the supplicant
514     * @return {@code true} if the operation succeeded
515     */
516    public boolean removeNetwork(int netId) {
517        try {
518            return mService.removeNetwork(netId);
519        } catch (RemoteException e) {
520            return false;
521        }
522    }
523
524    /**
525     * Allow a previously configured network to be associated with. If
526     * <code>disableOthers</code> is true, then all other configured
527     * networks are disabled, and an attempt to connect to the selected
528     * network is initiated. This may result in the asynchronous delivery
529     * of state change events.
530     * @param netId the ID of the network in the list of configured networks
531     * @param disableOthers if true, disable all other networks. The way to
532     * select a particular network to connect to is specify {@code true}
533     * for this parameter.
534     * @return {@code true} if the operation succeeded
535     */
536    public boolean enableNetwork(int netId, boolean disableOthers) {
537        try {
538            return mService.enableNetwork(netId, disableOthers);
539        } catch (RemoteException e) {
540            return false;
541        }
542    }
543
544    /**
545     * Disable a configured network. The specified network will not be
546     * a candidate for associating. This may result in the asynchronous
547     * delivery of state change events.
548     * @param netId the ID of the network as returned by {@link #addNetwork}.
549     * @return {@code true} if the operation succeeded
550     */
551    public boolean disableNetwork(int netId) {
552        try {
553            return mService.disableNetwork(netId);
554        } catch (RemoteException e) {
555            return false;
556        }
557    }
558
559    /**
560     * Disassociate from the currently active access point. This may result
561     * in the asynchronous delivery of state change events.
562     * @return {@code true} if the operation succeeded
563     */
564    public boolean disconnect() {
565        try {
566            mService.disconnect();
567            return true;
568        } catch (RemoteException e) {
569            return false;
570        }
571    }
572
573    /**
574     * Reconnect to the currently active access point, if we are currently
575     * disconnected. This may result in the asynchronous delivery of state
576     * change events.
577     * @return {@code true} if the operation succeeded
578     */
579    public boolean reconnect() {
580        try {
581            mService.reconnect();
582            return true;
583        } catch (RemoteException e) {
584            return false;
585        }
586    }
587
588    /**
589     * Reconnect to the currently active access point, even if we are already
590     * connected. This may result in the asynchronous delivery of state
591     * change events.
592     * @return {@code true} if the operation succeeded
593     */
594    public boolean reassociate() {
595        try {
596            mService.reassociate();
597            return true;
598        } catch (RemoteException e) {
599            return false;
600        }
601    }
602
603    /**
604     * Check that the supplicant daemon is responding to requests.
605     * @return {@code true} if we were able to communicate with the supplicant and
606     * it returned the expected response to the PING message.
607     */
608    public boolean pingSupplicant() {
609        if (mService == null)
610            return false;
611        try {
612            return mService.pingSupplicant();
613        } catch (RemoteException e) {
614            return false;
615        }
616    }
617
618    /**
619     * Request a scan for access points. Returns immediately. The availability
620     * of the results is made known later by means of an asynchronous event sent
621     * on completion of the scan.
622     * @return {@code true} if the operation succeeded, i.e., the scan was initiated
623     */
624    public boolean startScan() {
625        try {
626            mService.startScan(false);
627            return true;
628        } catch (RemoteException e) {
629            return false;
630        }
631    }
632
633    /**
634     * Request a scan for access points. Returns immediately. The availability
635     * of the results is made known later by means of an asynchronous event sent
636     * on completion of the scan.
637     * This is a variant of startScan that forces an active scan, even if passive
638     * scans are the current default
639     * @return {@code true} if the operation succeeded, i.e., the scan was initiated
640     *
641     * @hide
642     */
643    public boolean startScanActive() {
644        try {
645            mService.startScan(true);
646            return true;
647        } catch (RemoteException e) {
648            return false;
649        }
650    }
651
652    /**
653     * Return dynamic information about the current Wi-Fi connection, if any is active.
654     * @return the Wi-Fi information, contained in {@link WifiInfo}.
655     */
656    public WifiInfo getConnectionInfo() {
657        try {
658            return mService.getConnectionInfo();
659        } catch (RemoteException e) {
660            return null;
661        }
662    }
663
664    /**
665     * Return the results of the latest access point scan.
666     * @return the list of access points found in the most recent scan.
667     */
668    public List<ScanResult> getScanResults() {
669        try {
670            return mService.getScanResults();
671        } catch (RemoteException e) {
672            return null;
673        }
674    }
675
676    /**
677     * Tell the supplicant to persist the current list of configured networks.
678     * <p>
679     * Note: It is possible for this method to change the network IDs of
680     * existing networks. You should assume the network IDs can be different
681     * after calling this method.
682     *
683     * @return {@code true} if the operation succeeded
684     */
685    public boolean saveConfiguration() {
686        try {
687            return mService.saveConfiguration();
688        } catch (RemoteException e) {
689            return false;
690        }
691    }
692
693    /**
694     * Set the country code.
695     * @param countryCode country code in ISO 3166 format.
696     * @param persist {@code true} if this needs to be remembered
697     *
698     * @hide
699     */
700    public void setCountryCode(String country, boolean persist) {
701        try {
702            mService.setCountryCode(country, persist);
703        } catch (RemoteException e) { }
704    }
705
706    /**
707     * Set the operational frequency band.
708     * @param band  One of
709     *     {@link #WIFI_FREQUENCY_BAND_AUTO},
710     *     {@link #WIFI_FREQUENCY_BAND_5GHZ},
711     *     {@link #WIFI_FREQUENCY_BAND_2GHZ},
712     * @param persist {@code true} if this needs to be remembered
713     * @hide
714     */
715    public void setFrequencyBand(int band, boolean persist) {
716        try {
717            mService.setFrequencyBand(band, persist);
718        } catch (RemoteException e) { }
719    }
720
721    /**
722     * Get the operational frequency band.
723     * @return One of
724     *     {@link #WIFI_FREQUENCY_BAND_AUTO},
725     *     {@link #WIFI_FREQUENCY_BAND_5GHZ},
726     *     {@link #WIFI_FREQUENCY_BAND_2GHZ} or
727     *     {@code -1} on failure.
728     * @hide
729     */
730    public int getFrequencyBand() {
731        try {
732            return mService.getFrequencyBand();
733        } catch (RemoteException e) {
734            return -1;
735        }
736    }
737
738    /**
739     * Check if the chipset supports dual frequency band (2.4 GHz and 5 GHz)
740     * @return {@code true} if supported, {@code false} otherwise.
741     * @hide
742     */
743    public boolean isDualBandSupported() {
744        try {
745            return mService.isDualBandSupported();
746        } catch (RemoteException e) {
747            return false;
748        }
749    }
750
751    /**
752     * Return the DHCP-assigned addresses from the last successful DHCP request,
753     * if any.
754     * @return the DHCP information
755     */
756    public DhcpInfo getDhcpInfo() {
757        try {
758            return mService.getDhcpInfo();
759        } catch (RemoteException e) {
760            return null;
761        }
762    }
763
764
765    /**
766     * Enable or disable Wi-Fi.
767     * @param enabled {@code true} to enable, {@code false} to disable.
768     * @return {@code true} if the operation succeeds (or if the existing state
769     *         is the same as the requested state).
770     */
771    public boolean setWifiEnabled(boolean enabled) {
772        try {
773            return mService.setWifiEnabled(enabled);
774        } catch (RemoteException e) {
775            return false;
776        }
777    }
778
779    /**
780     * Gets the Wi-Fi enabled state.
781     * @return One of {@link #WIFI_STATE_DISABLED},
782     *         {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED},
783     *         {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN}
784     * @see #isWifiEnabled()
785     */
786    public int getWifiState() {
787        try {
788            return mService.getWifiEnabledState();
789        } catch (RemoteException e) {
790            return WIFI_STATE_UNKNOWN;
791        }
792    }
793
794    /**
795     * Return whether Wi-Fi is enabled or disabled.
796     * @return {@code true} if Wi-Fi is enabled
797     * @see #getWifiState()
798     */
799    public boolean isWifiEnabled() {
800        return getWifiState() == WIFI_STATE_ENABLED;
801    }
802
803    /**
804     * Calculates the level of the signal. This should be used any time a signal
805     * is being shown.
806     *
807     * @param rssi The power of the signal measured in RSSI.
808     * @param numLevels The number of levels to consider in the calculated
809     *            level.
810     * @return A level of the signal, given in the range of 0 to numLevels-1
811     *         (both inclusive).
812     */
813    public static int calculateSignalLevel(int rssi, int numLevels) {
814        if (rssi <= MIN_RSSI) {
815            return 0;
816        } else if (rssi >= MAX_RSSI) {
817            return numLevels - 1;
818        } else {
819            float inputRange = (MAX_RSSI - MIN_RSSI);
820            float outputRange = (numLevels - 1);
821            return (int)((float)(rssi - MIN_RSSI) * outputRange / inputRange);
822        }
823    }
824
825    /**
826     * Compares two signal strengths.
827     *
828     * @param rssiA The power of the first signal measured in RSSI.
829     * @param rssiB The power of the second signal measured in RSSI.
830     * @return Returns <0 if the first signal is weaker than the second signal,
831     *         0 if the two signals have the same strength, and >0 if the first
832     *         signal is stronger than the second signal.
833     */
834    public static int compareSignalLevel(int rssiA, int rssiB) {
835        return rssiA - rssiB;
836    }
837
838    /**
839     * Start AccessPoint mode with the specified
840     * configuration. If the radio is already running in
841     * AP mode, update the new configuration
842     * Note that starting in access point mode disables station
843     * mode operation
844     * @param wifiConfig SSID, security and channel details as
845     *        part of WifiConfiguration
846     * @return {@code true} if the operation succeeds, {@code false} otherwise
847     *
848     * @hide Dont open up yet
849     */
850    public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
851        try {
852            return mService.setWifiApEnabled(wifiConfig, enabled);
853        } catch (RemoteException e) {
854            return false;
855        }
856    }
857
858    /**
859     * Gets the Wi-Fi enabled state.
860     * @return One of {@link #WIFI_AP_STATE_DISABLED},
861     *         {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
862     *         {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
863     * @see #isWifiApEnabled()
864     *
865     * @hide Dont open yet
866     */
867    public int getWifiApState() {
868        try {
869            return mService.getWifiApEnabledState();
870        } catch (RemoteException e) {
871            return WIFI_AP_STATE_FAILED;
872        }
873    }
874
875    /**
876     * Return whether Wi-Fi AP is enabled or disabled.
877     * @return {@code true} if Wi-Fi AP is enabled
878     * @see #getWifiApState()
879     *
880     * @hide Dont open yet
881     */
882    public boolean isWifiApEnabled() {
883        return getWifiApState() == WIFI_AP_STATE_ENABLED;
884    }
885
886    /**
887     * Gets the Wi-Fi AP Configuration.
888     * @return AP details in WifiConfiguration
889     *
890     * @hide Dont open yet
891     */
892    public WifiConfiguration getWifiApConfiguration() {
893        try {
894            return mService.getWifiApConfiguration();
895        } catch (RemoteException e) {
896            return null;
897        }
898    }
899
900    /**
901     * Sets the Wi-Fi AP Configuration.
902     * @return {@code true} if the operation succeeded, {@code false} otherwise
903     *
904     * @hide Dont open yet
905     */
906    public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
907        try {
908            mService.setWifiApConfiguration(wifiConfig);
909            return true;
910        } catch (RemoteException e) {
911            return false;
912        }
913    }
914
915   /**
916     * Start the driver and connect to network.
917     *
918     * This function will over-ride WifiLock and device idle status. For example,
919     * even if the device is idle or there is only a scan-only lock held,
920     * a start wifi would mean that wifi connection is kept active until
921     * a stopWifi() is sent.
922     *
923     * This API is used by WifiStateTracker
924     *
925     * @return {@code true} if the operation succeeds else {@code false}
926     * @hide
927     */
928    public boolean startWifi() {
929        try {
930            mService.startWifi();
931            return true;
932        } catch (RemoteException e) {
933            return false;
934        }
935    }
936
937    /**
938     * Disconnect from a network (if any) and stop the driver.
939     *
940     * This function will over-ride WifiLock and device idle status. Wi-Fi
941     * stays inactive until a startWifi() is issued.
942     *
943     * This API is used by WifiStateTracker
944     *
945     * @return {@code true} if the operation succeeds else {@code false}
946     * @hide
947     */
948    public boolean stopWifi() {
949        try {
950            mService.stopWifi();
951            return true;
952        } catch (RemoteException e) {
953            return false;
954        }
955    }
956
957    /**
958     * Add a bssid to the supplicant blacklist
959     *
960     * This API is used by WifiWatchdogService
961     *
962     * @return {@code true} if the operation succeeds else {@code false}
963     * @hide
964     */
965    public boolean addToBlacklist(String bssid) {
966        try {
967            mService.addToBlacklist(bssid);
968            return true;
969        } catch (RemoteException e) {
970            return false;
971        }
972    }
973
974    /**
975     * Clear the supplicant blacklist
976     *
977     * This API is used by WifiWatchdogService
978     *
979     * @return {@code true} if the operation succeeds else {@code false}
980     * @hide
981     */
982    public boolean clearBlacklist() {
983        try {
984            mService.clearBlacklist();
985            return true;
986        } catch (RemoteException e) {
987            return false;
988        }
989    }
990
991    /* TODO: deprecate synchronous API and open up the following API */
992    /**
993     * Connect to a network with the given configuration. The network also
994     * gets added to the supplicant configuration.
995     *
996     * For a new network, this function is used instead of a
997     * sequence of addNetwork(), enableNetwork(), saveConfiguration() and
998     * reconnect()
999     *
1000     * @param config the set of variables that describe the configuration,
1001     *            contained in a {@link WifiConfiguration} object.
1002     * @hide
1003     */
1004    public void connectNetwork(WifiConfiguration config) {
1005        if (config == null) {
1006            return;
1007        }
1008        try {
1009            mService.connectNetworkWithConfig(config);
1010        } catch (RemoteException e) { }
1011    }
1012
1013    /**
1014     * Connect to a network with the given networkId.
1015     *
1016     * This function is used instead of a enableNetwork(), saveConfiguration() and
1017     * reconnect()
1018     *
1019     * @param networkId the network id identifiying the network in the
1020     *                supplicant configuration list
1021     * @hide
1022     */
1023    public void connectNetwork(int networkId) {
1024        if (networkId < 0) {
1025            return;
1026        }
1027        try {
1028            mService.connectNetworkWithId(networkId);
1029        } catch (RemoteException e) { }
1030    }
1031
1032    /**
1033     * Save the given network in the supplicant config. If the network already
1034     * exists, the configuration is updated. A new network is enabled
1035     * by default.
1036     *
1037     * For a new network, this function is used instead of a
1038     * sequence of addNetwork(), enableNetwork() and saveConfiguration().
1039     *
1040     * For an existing network, it accomplishes the task of updateNetwork()
1041     * and saveConfiguration()
1042     *
1043     * @param config the set of variables that describe the configuration,
1044     *            contained in a {@link WifiConfiguration} object.
1045     * @hide
1046     */
1047    public void saveNetwork(WifiConfiguration config) {
1048        if (config == null) {
1049            return;
1050        }
1051        try {
1052            mService.saveNetwork(config);
1053        } catch (RemoteException e) { }
1054    }
1055
1056    /**
1057     * Delete the network in the supplicant config.
1058     *
1059     * This function is used instead of a sequence of removeNetwork()
1060     * and saveConfiguration().
1061     *
1062     * @param config the set of variables that describe the configuration,
1063     *            contained in a {@link WifiConfiguration} object.
1064     * @hide
1065     */
1066    public void forgetNetwork(int netId) {
1067        if (netId < 0) {
1068            return;
1069        }
1070        try {
1071            mService.forgetNetwork(netId);
1072        } catch (RemoteException e) { }
1073    }
1074
1075    /**
1076     * Start Wi-fi protected setup push button Configuration
1077     *
1078     * @param bssid BSSID of the access point
1079     * @hide
1080     */
1081    public void startWpsPbc(String bssid) {
1082        try {
1083            mService.startWpsPbc(bssid);
1084        } catch (RemoteException e) { }
1085    }
1086
1087    /**
1088     * Start Wi-fi Protected Setup pin method configuration
1089     * with pin obtained from the access point
1090     *
1091     * @param bssid BSSID of the access point
1092     * @param apPin PIN issued by the access point
1093     *
1094     * @hide
1095     */
1096    public void startWpsWithPinFromAccessPoint(String bssid, int apPin) {
1097        try {
1098            mService.startWpsWithPinFromAccessPoint(bssid, apPin);
1099        } catch (RemoteException e) { }
1100    }
1101
1102    /**
1103     * Start Wi-fi Protected Setup pin method configuration
1104     * with pin obtained from the device
1105     *
1106     * @param bssid BSSID of the access point
1107     * @return pin generated by device
1108     * @hide
1109     */
1110    public int startWpsWithPinFromDevice(String bssid) {
1111        try {
1112            return mService.startWpsWithPinFromDevice(bssid);
1113        } catch (RemoteException e) {
1114            return -1;
1115        }
1116    }
1117
1118    /**
1119     * Allows an application to keep the Wi-Fi radio awake.
1120     * Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
1121     * Acquiring a WifiLock will keep the radio on until the lock is released.  Multiple
1122     * applications may hold WifiLocks, and the radio will only be allowed to turn off when no
1123     * WifiLocks are held in any application.
1124     *
1125     * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or
1126     * could function over a mobile network, if available.  A program that needs to download large
1127     * files should hold a WifiLock to ensure that the download will complete, but a program whose
1128     * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely
1129     * affecting battery life.
1130     *
1131     * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane
1132     * Mode.  They simply keep the radio from turning off when Wi-Fi is already on but the device
1133     * is idle.
1134     */
1135    public class WifiLock {
1136        private String mTag;
1137        private final IBinder mBinder;
1138        private int mRefCount;
1139        int mLockType;
1140        private boolean mRefCounted;
1141        private boolean mHeld;
1142        private WorkSource mWorkSource;
1143
1144        private WifiLock(int lockType, String tag) {
1145            mTag = tag;
1146            mLockType = lockType;
1147            mBinder = new Binder();
1148            mRefCount = 0;
1149            mRefCounted = true;
1150            mHeld = false;
1151        }
1152
1153        /**
1154         * Locks the Wi-Fi radio on until {@link #release} is called.
1155         *
1156         * If this WifiLock is reference-counted, each call to {@code acquire} will increment the
1157         * reference count, and the radio will remain locked as long as the reference count is
1158         * above zero.
1159         *
1160         * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock
1161         * the radio, but subsequent calls will be ignored.  Only one call to {@link #release}
1162         * will be required, regardless of the number of times that {@code acquire} is called.
1163         */
1164        public void acquire() {
1165            synchronized (mBinder) {
1166                if (mRefCounted ? (++mRefCount > 0) : (!mHeld)) {
1167                    try {
1168                        mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource);
1169                        synchronized (WifiManager.this) {
1170                            if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
1171                                mService.releaseWifiLock(mBinder);
1172                                throw new UnsupportedOperationException(
1173                                            "Exceeded maximum number of wifi locks");
1174                            }
1175                            mActiveLockCount++;
1176                        }
1177                    } catch (RemoteException ignore) {
1178                    }
1179                    mHeld = true;
1180                }
1181            }
1182        }
1183
1184        /**
1185         * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle.
1186         *
1187         * If this WifiLock is reference-counted, each call to {@code release} will decrement the
1188         * reference count, and the radio will be unlocked only when the reference count reaches
1189         * zero.  If the reference count goes below zero (that is, if {@code release} is called
1190         * a greater number of times than {@link #acquire}), an exception is thrown.
1191         *
1192         * If this WifiLock is not reference-counted, the first call to {@code release} (after
1193         * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent
1194         * calls will be ignored.
1195         */
1196        public void release() {
1197            synchronized (mBinder) {
1198                if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
1199                    try {
1200                        mService.releaseWifiLock(mBinder);
1201                        synchronized (WifiManager.this) {
1202                            mActiveLockCount--;
1203                        }
1204                    } catch (RemoteException ignore) {
1205                    }
1206                    mHeld = false;
1207                }
1208                if (mRefCount < 0) {
1209                    throw new RuntimeException("WifiLock under-locked " + mTag);
1210                }
1211            }
1212        }
1213
1214        /**
1215         * Controls whether this is a reference-counted or non-reference-counted WifiLock.
1216         *
1217         * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and
1218         * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire}
1219         * has been balanced with a call to {@link #release}.  Non-reference-counted WifiLocks
1220         * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the
1221         * radio whenever {@link #release} is called and it is locked.
1222         *
1223         * @param refCounted true if this WifiLock should keep a reference count
1224         */
1225        public void setReferenceCounted(boolean refCounted) {
1226            mRefCounted = refCounted;
1227        }
1228
1229        /**
1230         * Checks whether this WifiLock is currently held.
1231         *
1232         * @return true if this WifiLock is held, false otherwise
1233         */
1234        public boolean isHeld() {
1235            synchronized (mBinder) {
1236                return mHeld;
1237            }
1238        }
1239
1240        public void setWorkSource(WorkSource ws) {
1241            synchronized (mBinder) {
1242                if (ws != null && ws.size() == 0) {
1243                    ws = null;
1244                }
1245                boolean changed = true;
1246                if (ws == null) {
1247                    mWorkSource = null;
1248                } else if (mWorkSource == null) {
1249                    changed = mWorkSource != null;
1250                    mWorkSource = new WorkSource(ws);
1251                } else {
1252                    changed = mWorkSource.diff(ws);
1253                    if (changed) {
1254                        mWorkSource.set(ws);
1255                    }
1256                }
1257                if (changed && mHeld) {
1258                    try {
1259                        mService.updateWifiLockWorkSource(mBinder, mWorkSource);
1260                    } catch (RemoteException e) {
1261                    }
1262                }
1263            }
1264        }
1265
1266        public String toString() {
1267            String s1, s2, s3;
1268            synchronized (mBinder) {
1269                s1 = Integer.toHexString(System.identityHashCode(this));
1270                s2 = mHeld ? "held; " : "";
1271                if (mRefCounted) {
1272                    s3 = "refcounted: refcount = " + mRefCount;
1273                } else {
1274                    s3 = "not refcounted";
1275                }
1276                return "WifiLock{ " + s1 + "; " + s2 + s3 + " }";
1277            }
1278        }
1279
1280        @Override
1281        protected void finalize() throws Throwable {
1282            super.finalize();
1283            synchronized (mBinder) {
1284                if (mHeld) {
1285                    try {
1286                        mService.releaseWifiLock(mBinder);
1287                        synchronized (WifiManager.this) {
1288                            mActiveLockCount--;
1289                        }
1290                    } catch (RemoteException ignore) {
1291                    }
1292                }
1293            }
1294        }
1295    }
1296
1297    /**
1298     * Creates a new WifiLock.
1299     *
1300     * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL},
1301     * and {@link #WIFI_MODE_SCAN_ONLY} for 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