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