WifiManager.java revision b5010cc3c33c74cc406a70f34f93d330a3f0db6a
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;
26
27import java.util.List;
28
29/**
30 * This class provides the primary API for managing all aspects of Wi-Fi
31 * connectivity. Get an instance of this class by calling
32 * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.WIFI_SERVICE)}.
33
34 * It deals with several categories of items:
35 * <ul>
36 * <li>The list of configured networks. The list can be viewed and updated,
37 * and attributes of individual entries can be modified.</li>
38 * <li>The currently active Wi-Fi network, if any. Connectivity can be
39 * established or torn down, and dynamic information about the state of
40 * the network can be queried.</li>
41 * <li>Results of access point scans, containing enough information to
42 * make decisions about what access point to connect to.</li>
43 * <li>It defines the names of various Intent actions that are broadcast
44 * upon any sort of change in Wi-Fi state.
45 * </ul>
46 * This is the API to use when performing Wi-Fi specific operations. To
47 * perform operations that pertain to network connectivity at an abstract
48 * level, use {@link android.net.ConnectivityManager}.
49 */
50public class WifiManager {
51
52    // Supplicant error codes:
53    /**
54     * The error code if there was a problem authenticating.
55     */
56    public static final int ERROR_AUTHENTICATING = 1;
57
58    /**
59     * Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
60     * enabling, disabling, or unknown. One extra provides this state as an int.
61     * Another extra provides the previous state, if available.
62     *
63     * @see #EXTRA_WIFI_STATE
64     * @see #EXTRA_PREVIOUS_WIFI_STATE
65     */
66    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
67    public static final String WIFI_STATE_CHANGED_ACTION =
68        "android.net.wifi.WIFI_STATE_CHANGED";
69    /**
70     * The lookup key for an int that indicates whether Wi-Fi is enabled,
71     * disabled, enabling, disabling, or unknown.  Retrieve it with
72     * {@link android.content.Intent#getIntExtra(String,int)}.
73     *
74     * @see #WIFI_STATE_DISABLED
75     * @see #WIFI_STATE_DISABLING
76     * @see #WIFI_STATE_ENABLED
77     * @see #WIFI_STATE_ENABLING
78     * @see #WIFI_STATE_UNKNOWN
79     */
80    public static final String EXTRA_WIFI_STATE = "wifi_state";
81    /**
82     * The previous Wi-Fi state.
83     *
84     * @see #EXTRA_WIFI_STATE
85     */
86    public static final String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
87
88    /**
89     * Wi-Fi is currently being disabled. The state will change to {@link #WIFI_STATE_DISABLED} if
90     * it finishes successfully.
91     *
92     * @see #WIFI_STATE_CHANGED_ACTION
93     * @see #getWifiState()
94     */
95    public static final int WIFI_STATE_DISABLING = 0;
96    /**
97     * Wi-Fi is disabled.
98     *
99     * @see #WIFI_STATE_CHANGED_ACTION
100     * @see #getWifiState()
101     */
102    public static final int WIFI_STATE_DISABLED = 1;
103    /**
104     * Wi-Fi is currently being enabled. The state will change to {@link #WIFI_STATE_ENABLED} if
105     * it finishes successfully.
106     *
107     * @see #WIFI_STATE_CHANGED_ACTION
108     * @see #getWifiState()
109     */
110    public static final int WIFI_STATE_ENABLING = 2;
111    /**
112     * Wi-Fi is enabled.
113     *
114     * @see #WIFI_STATE_CHANGED_ACTION
115     * @see #getWifiState()
116     */
117    public static final int WIFI_STATE_ENABLED = 3;
118    /**
119     * Wi-Fi is in an unknown state. This state will occur when an error happens while enabling
120     * or disabling.
121     *
122     * @see #WIFI_STATE_CHANGED_ACTION
123     * @see #getWifiState()
124     */
125    public static final int WIFI_STATE_UNKNOWN = 4;
126
127    /**
128     * Broadcast intent action indicating that a connection to the supplicant has
129     * been established (and it is now possible
130     * to perform Wi-Fi operations) or the connection to the supplicant has been
131     * lost. One extra provides the connection state as a boolean, where {@code true}
132     * means CONNECTED.
133     * @see #EXTRA_SUPPLICANT_CONNECTED
134     */
135    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
136    public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION =
137        "android.net.wifi.supplicant.CONNECTION_CHANGE";
138    /**
139     * The lookup key for a boolean that indicates whether a connection to
140     * the supplicant daemon has been gained or lost. {@code true} means
141     * a connection now exists.
142     * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
143     */
144    public static final String EXTRA_SUPPLICANT_CONNECTED = "connected";
145    /**
146     * Broadcast intent action indicating that the state of Wi-Fi connectivity
147     * has changed. One extra provides the new state
148     * in the form of a {@link android.net.NetworkInfo} object. If the new state is
149     * CONNECTED, a second extra may provide the BSSID of the access point,
150     * as a {@code String}.
151     * @see #EXTRA_NETWORK_INFO
152     * @see #EXTRA_BSSID
153     */
154    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
155    public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
156    /**
157     * The lookup key for a {@link android.net.NetworkInfo} object associated with the
158     * Wi-Fi network. Retrieve with
159     * {@link android.content.Intent#getParcelableExtra(String)}.
160     */
161    public static final String EXTRA_NETWORK_INFO = "networkInfo";
162    /**
163     * The lookup key for a String giving the BSSID of the access point to which
164     * we are connected. Only present when the new state is CONNECTED.
165     * Retrieve with
166     * {@link android.content.Intent#getStringExtra(String)}.
167     */
168    public static final String EXTRA_BSSID = "bssid";
169    /**
170     * Broadcast intent action indicating that the state of establishing a connection to
171     * an access point has changed.One extra provides the new
172     * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and
173     * is not generally the most useful thing to look at if you are just interested in
174     * the overall state of connectivity.
175     * @see #EXTRA_NEW_STATE
176     * @see #EXTRA_SUPPLICANT_ERROR
177     */
178    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
179    public static final String SUPPLICANT_STATE_CHANGED_ACTION =
180        "android.net.wifi.supplicant.STATE_CHANGE";
181    /**
182     * The lookup key for a {@link SupplicantState} describing the new state
183     * Retrieve with
184     * {@link android.content.Intent#getParcelableExtra(String)}.
185     */
186    public static final String EXTRA_NEW_STATE = "newState";
187
188    /**
189     * The lookup key for a {@link SupplicantState} describing the supplicant
190     * error code if any
191     * Retrieve with
192     * {@link android.content.Intent#getIntExtra(String, int)}.
193     * @see #ERROR_AUTHENTICATING
194     */
195    public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError";
196
197    /**
198     * An access point scan has completed, and results are available from the supplicant.
199     * Call {@link #getScanResults()} to obtain the results.
200     */
201    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
202    public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
203    /**
204     * The RSSI (signal strength) has changed.
205     * @see #EXTRA_NEW_RSSI
206     */
207    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
208    public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
209    /**
210     * The lookup key for an {@code int} giving the new RSSI in dBm.
211     */
212    public static final String EXTRA_NEW_RSSI = "newRssi";
213
214    /**
215     * The network IDs of the configured networks could have changed.
216     */
217    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
218    public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
219
220    /**
221     * Activity Action: Pick a Wi-Fi network to connect to.
222     * <p>Input: Nothing.
223     * <p>Output: Nothing.
224     */
225    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
226    public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
227
228    /**
229     * In this Wi-Fi lock mode, Wi-Fi will be kept active,
230     * and will behave normally, i.e., it will attempt to automatically
231     * establish a connection to a remembered access point that is
232     * within range, and will do periodic scans if there are remembered
233     * access points but none are in range.
234     */
235    public static final int WIFI_MODE_FULL = 1;
236    /**
237     * In this Wi-Fi lock mode, Wi-Fi will be kept active,
238     * but the only operation that will be supported is initiation of
239     * scans, and the subsequent reporting of scan results. No attempts
240     * will be made to automatically connect to remembered access points,
241     * nor will periodic scans be automatically performed looking for
242     * remembered access points. Scans must be explicitly requested by
243     * an application in this mode.
244     */
245    public static final int WIFI_MODE_SCAN_ONLY = 2;
246
247    /** Anything worse than or equal to this will show 0 bars. */
248    private static final int MIN_RSSI = -100;
249
250    /** Anything better than or equal to this will show the max bars. */
251    private static final int MAX_RSSI = -55;
252
253    IWifiManager mService;
254    Handler mHandler;
255
256    /**
257     * Create a new WifiManager instance.
258     * Applications will almost always want to use
259     * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
260     * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
261     * @param service the Binder interface
262     * @param handler target for messages
263     * @hide - hide this because it takes in a parameter of type IWifiManager, which
264     * is a system private class.
265     */
266    public WifiManager(IWifiManager service, Handler handler) {
267        mService = service;
268        mHandler = handler;
269    }
270
271    /**
272     * Return a list of all the networks configured in the supplicant.
273     * Not all fields of WifiConfiguration are returned. Only the following
274     * fields are filled in:
275     * <ul>
276     * <li>networkId</li>
277     * <li>SSID</li>
278     * <li>BSSID</li>
279     * <li>priority</li>
280     * <li>allowedProtocols</li>
281     * <li>allowedKeyManagement</li>
282     * <li>allowedAuthAlgorithms</li>
283     * <li>allowedPairwiseCiphers</li>
284     * <li>allowedGroupCiphers</li>
285     * </ul>
286     * @return a list of network configurations in the form of a list
287     * of {@link WifiConfiguration} objects.
288     */
289    public List<WifiConfiguration> getConfiguredNetworks() {
290        try {
291            return mService.getConfiguredNetworks();
292        } catch (RemoteException e) {
293            return null;
294        }
295    }
296
297    /**
298     * Add a new network description to the set of configured networks.
299     * The {@code networkId} field of the supplied configuration object
300     * is ignored.
301     * <p/>
302     * The new network will be marked DISABLED by default. To enable it,
303     * called {@link #enableNetwork}.
304     *
305     * @param config the set of variables that describe the configuration,
306     *            contained in a {@link WifiConfiguration} object.
307     * @return the ID of the newly created network description. This is used in
308     *         other operations to specified the network to be acted upon.
309     *         Returns {@code -1} on failure.
310     */
311    public int addNetwork(WifiConfiguration config) {
312        if (config == null) {
313            return -1;
314        }
315        config.networkId = -1;
316        return addOrUpdateNetwork(config);
317    }
318
319    /**
320     * Update the network description of an existing configured network.
321     *
322     * @param config the set of variables that describe the configuration,
323     *            contained in a {@link WifiConfiguration} object. It may
324     *            be sparse, so that only the items that are being changed
325     *            are non-<code>null</code>. The {@code networkId} field
326     *            must be set to the ID of the existing network being updated.
327     * @return Returns the {@code networkId} of the supplied
328     *         {@code WifiConfiguration} on success.
329     *         <br/>
330     *         Returns {@code -1} on failure, including when the {@code networkId}
331     *         field of the {@code WifiConfiguration} does not refer to an
332     *         existing network.
333     */
334    public int updateNetwork(WifiConfiguration config) {
335        if (config == null || config.networkId < 0) {
336            return -1;
337        }
338        return addOrUpdateNetwork(config);
339    }
340
341    /**
342     * Internal method for doing the RPC that creates a new network description
343     * or updates an existing one.
344     *
345     * @param config The possibly sparse object containing the variables that
346     *         are to set or updated in the network description.
347     * @return the ID of the network on success, {@code -1} on failure.
348     */
349    private int addOrUpdateNetwork(WifiConfiguration config) {
350        try {
351            return mService.addOrUpdateNetwork(config);
352        } catch (RemoteException e) {
353            return -1;
354        }
355    }
356
357    /**
358     * Remove the specified network from the list of configured networks.
359     * This may result in the asynchronous delivery of state change
360     * events.
361     * @param netId the integer that identifies the network configuration
362     * to the supplicant
363     * @return {@code true} if the operation succeeded
364     */
365    public boolean removeNetwork(int netId) {
366        try {
367            return mService.removeNetwork(netId);
368        } catch (RemoteException e) {
369            return false;
370        }
371    }
372
373    /**
374     * Allow a previously configured network to be associated with. If
375     * <code>disableOthers</code> is true, then all other configured
376     * networks are disabled, and an attempt to connect to the selected
377     * network is initiated. This may result in the asynchronous delivery
378     * of state change events.
379     * @param netId the ID of the network in the list of configured networks
380     * @param disableOthers if true, disable all other networks. The way to
381     * select a particular network to connect to is specify {@code true}
382     * for this parameter.
383     * @return {@code true} if the operation succeeded
384     */
385    public boolean enableNetwork(int netId, boolean disableOthers) {
386        try {
387            return mService.enableNetwork(netId, disableOthers);
388        } catch (RemoteException e) {
389            return false;
390        }
391    }
392
393    /**
394     * Disable a configured network. The specified network will not be
395     * a candidate for associating. This may result in the asynchronous
396     * delivery of state change events.
397     * @param netId the ID of the network as returned by {@link #addNetwork}.
398     * @return {@code true} if the operation succeeded
399     */
400    public boolean disableNetwork(int netId) {
401        try {
402            return mService.disableNetwork(netId);
403        } catch (RemoteException e) {
404            return false;
405        }
406    }
407
408    /**
409     * Disassociate from the currently active access point. This may result
410     * in the asynchronous delivery of state change events.
411     * @return {@code true} if the operation succeeded
412     */
413    public boolean disconnect() {
414        try {
415            return mService.disconnect();
416        } catch (RemoteException e) {
417            return false;
418        }
419    }
420
421    /**
422     * Reconnect to the currently active access point, if we are currently
423     * disconnected. This may result in the asynchronous delivery of state
424     * change events.
425     * @return {@code true} if the operation succeeded
426     */
427    public boolean reconnect() {
428        try {
429            return mService.reconnect();
430        } catch (RemoteException e) {
431            return false;
432        }
433    }
434
435    /**
436     * Reconnect to the currently active access point, even if we are already
437     * connected. This may result in the asynchronous delivery of state
438     * change events.
439     * @return {@code true} if the operation succeeded
440     */
441    public boolean reassociate() {
442        try {
443            return mService.reassociate();
444        } catch (RemoteException e) {
445            return false;
446        }
447    }
448
449    /**
450     * Check that the supplicant daemon is responding to requests.
451     * @return {@code true} if we were able to communicate with the supplicant and
452     * it returned the expected response to the PING message.
453     */
454    public boolean pingSupplicant() {
455        if (mService == null)
456            return false;
457        try {
458            return mService.pingSupplicant();
459        } catch (RemoteException e) {
460            return false;
461        }
462    }
463
464    /**
465     * Request a scan for access points. Returns immediately. The availability
466     * of the results is made known later by means of an asynchronous event sent
467     * on completion of the scan.
468     * @return {@code true} if the operation succeeded, i.e., the scan was initiated
469     */
470    public boolean  startScan() {
471        try {
472            return mService.startScan();
473        } catch (RemoteException e) {
474            return false;
475        }
476    }
477
478    /**
479     * Return dynamic information about the current Wi-Fi connection, if any is active.
480     * @return the Wi-Fi information, contained in {@link WifiInfo}.
481     */
482    public WifiInfo getConnectionInfo() {
483        try {
484            return mService.getConnectionInfo();
485        } catch (RemoteException e) {
486            return null;
487        }
488    }
489
490    /**
491     * Return the results of the latest access point scan.
492     * @return the list of access points found in the most recent scan.
493     */
494    public List<ScanResult> getScanResults() {
495        try {
496            return mService.getScanResults();
497        } catch (RemoteException e) {
498            return null;
499        }
500    }
501
502    /**
503     * Tell the supplicant to persist the current list of configured networks.
504     * <p>
505     * Note: It is possible for this method to change the network IDs of
506     * existing networks. You should assume the network IDs can be different
507     * after calling this method.
508     *
509     * @return {@code true} if the operation succeeded
510     */
511    public boolean saveConfiguration() {
512        try {
513            return mService.saveConfiguration();
514        } catch (RemoteException e) {
515            return false;
516        }
517    }
518
519    /**
520     * Return the number of frequency channels that are allowed
521     * to be used in the current regulatory domain.
522     * @return the number of allowed channels, or {@code -1} if an error occurs
523     *
524     * @hide pending API council
525     */
526    public int getNumAllowedChannels() {
527        try {
528            return mService.getNumAllowedChannels();
529        } catch (RemoteException e) {
530            return -1;
531        }
532    }
533
534    /**
535     * Set the number of frequency channels that are allowed to be used
536     * in the current regulatory domain. This method should be used only
537     * if the correct number of channels cannot be determined automatically
538     * for some reason.
539     * @param numChannels the number of allowed channels. Must be greater than 0
540     * and less than or equal to 16.
541     * @param persist {@code true} if you want this remembered
542     * @return {@code true} if the operation succeeds, {@code false} otherwise, e.g.,
543     * {@code numChannels} is out of range.
544     *
545     * @hide pending API council
546     */
547    public boolean setNumAllowedChannels(int numChannels, boolean persist) {
548        try {
549            return mService.setNumAllowedChannels(numChannels, persist);
550        } catch (RemoteException e) {
551            return false;
552        }
553    }
554
555    /**
556     * Return the list of valid values for the number of allowed radio channels
557     * for various regulatory domains.
558     * @return the list of channel counts, or {@code null} if the operation fails
559     *
560     * @hide pending API council review
561     */
562    public int[] getValidChannelCounts() {
563        try {
564            return mService.getValidChannelCounts();
565        } catch (RemoteException e) {
566            return null;
567        }
568   }
569
570    /**
571     * Return the DHCP-assigned addresses from the last successful DHCP request,
572     * if any.
573     * @return the DHCP information
574     */
575    public DhcpInfo getDhcpInfo() {
576        try {
577            return mService.getDhcpInfo();
578        } catch (RemoteException e) {
579            return null;
580        }
581    }
582
583
584    /**
585     * Enable or disable Wi-Fi.
586     * @param enabled {@code true} to enable, {@code false} to disable.
587     * @return {@code true} if the operation succeeds (or if the existing state
588     *         is the same as the requested state).
589     */
590    public boolean setWifiEnabled(boolean enabled) {
591        try {
592            return mService.setWifiEnabled(enabled);
593        } catch (RemoteException e) {
594            return false;
595        }
596    }
597
598    /**
599     * Gets the Wi-Fi enabled state.
600     * @return One of {@link #WIFI_STATE_DISABLED},
601     *         {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED},
602     *         {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN}
603     * @see #isWifiEnabled()
604     */
605    public int getWifiState() {
606        try {
607            return mService.getWifiEnabledState();
608        } catch (RemoteException e) {
609            return WIFI_STATE_UNKNOWN;
610        }
611    }
612
613    /**
614     * Return whether Wi-Fi is enabled or disabled.
615     * @return {@code true} if Wi-Fi is enabled
616     * @see #getWifiState()
617     */
618    public boolean isWifiEnabled() {
619        return getWifiState() == WIFI_STATE_ENABLED;
620    }
621
622    /**
623     * Calculates the level of the signal. This should be used any time a signal
624     * is being shown.
625     *
626     * @param rssi The power of the signal measured in RSSI.
627     * @param numLevels The number of levels to consider in the calculated
628     *            level.
629     * @return A level of the signal, given in the range of 0 to numLevels-1
630     *         (both inclusive).
631     */
632    public static int calculateSignalLevel(int rssi, int numLevels) {
633        if (rssi <= MIN_RSSI) {
634            return 0;
635        } else if (rssi >= MAX_RSSI) {
636            return numLevels - 1;
637        } else {
638            int partitionSize = (MAX_RSSI - MIN_RSSI) / (numLevels - 1);
639            return (rssi - MIN_RSSI) / partitionSize;
640        }
641    }
642
643    /**
644     * Compares two signal strengths.
645     *
646     * @param rssiA The power of the first signal measured in RSSI.
647     * @param rssiB The power of the second signal measured in RSSI.
648     * @return Returns <0 if the first signal is weaker than the second signal,
649     *         0 if the two signals have the same strength, and >0 if the first
650     *         signal is stronger than the second signal.
651     */
652    public static int compareSignalLevel(int rssiA, int rssiB) {
653        return rssiA - rssiB;
654    }
655
656    /**
657     * Allows an application to keep the Wi-Fi radio awake.
658     * Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
659     * Acquiring a WifiLock will keep the radio on until the lock is released.  Multiple
660     * applications may hold WifiLocks, and the radio will only be allowed to turn off when no
661     * WifiLocks are held in any application.
662     *
663     * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or
664     * could function over a mobile network, if available.  A program that needs to download large
665     * files should hold a WifiLock to ensure that the download will complete, but a program whose
666     * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely
667     * affecting battery life.
668     *
669     * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane
670     * Mode.  They simply keep the radio from turning off when Wi-Fi is already on but the device
671     * is idle.
672     */
673    public class WifiLock {
674        private String mTag;
675        private final IBinder mBinder;
676        private int mRefCount;
677        int mLockType;
678        private boolean mRefCounted;
679        private boolean mHeld;
680
681        private WifiLock(int lockType, String tag) {
682            mTag = tag;
683            mLockType = lockType;
684            mBinder = new Binder();
685            mRefCount = 0;
686            mRefCounted = true;
687            mHeld = false;
688        }
689
690        /**
691         * Locks the Wi-Fi radio on until {@link #release} is called.
692         *
693         * If this WifiLock is reference-counted, each call to {@code acquire} will increment the
694         * reference count, and the radio will remain locked as long as the reference count is
695         * above zero.
696         *
697         * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock
698         * the radio, but subsequent calls will be ignored.  Only one call to {@link #release}
699         * will be required, regardless of the number of times that {@code acquire} is called.
700         */
701        public void acquire() {
702            synchronized (mBinder) {
703                if (mRefCounted ? (++mRefCount > 0) : (!mHeld)) {
704                    try {
705                        mService.acquireWifiLock(mBinder, mLockType, mTag);
706                    } catch (RemoteException ignore) {
707                    }
708                    mHeld = true;
709                }
710            }
711        }
712
713        /**
714         * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle.
715         *
716         * If this WifiLock is reference-counted, each call to {@code release} will decrement the
717         * reference count, and the radio will be unlocked only when the reference count reaches
718         * zero.  If the reference count goes below zero (that is, if {@code release} is called
719         * a greater number of times than {@link #acquire}), an exception is thrown.
720         *
721         * If this WifiLock is not reference-counted, the first call to {@code release} (after
722         * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent
723         * calls will be ignored.
724         */
725        public void release() {
726            synchronized (mBinder) {
727                if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
728                    try {
729                        mService.releaseWifiLock(mBinder);
730                    } catch (RemoteException ignore) {
731                    }
732                    mHeld = false;
733                }
734                if (mRefCount < 0) {
735                    throw new RuntimeException("WifiLock under-locked " + mTag);
736                }
737            }
738        }
739
740        /**
741         * Controls whether this is a reference-counted or non-reference-counted WifiLock.
742         *
743         * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and
744         * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire}
745         * has been balanced with a call to {@link #release}.  Non-reference-counted WifiLocks
746         * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the
747         * radio whenever {@link #release} is called and it is locked.
748         *
749         * @param refCounted true if this WifiLock should keep a reference count
750         */
751        public void setReferenceCounted(boolean refCounted) {
752            mRefCounted = refCounted;
753        }
754
755        /**
756         * Checks whether this WifiLock is currently held.
757         *
758         * @return true if this WifiLock is held, false otherwise
759         */
760        public boolean isHeld() {
761            synchronized (mBinder) {
762                return mHeld;
763            }
764        }
765
766        public String toString() {
767            String s1, s2, s3;
768            synchronized (mBinder) {
769                s1 = Integer.toHexString(System.identityHashCode(this));
770                s2 = mHeld ? "held; " : "";
771                if (mRefCounted) {
772                    s3 = "refcounted: refcount = " + mRefCount;
773                } else {
774                    s3 = "not refcounted";
775                }
776                return "WifiLock{ " + s1 + "; " + s2 + s3 + " }";
777            }
778        }
779
780        @Override
781        protected void finalize() throws Throwable {
782            super.finalize();
783            synchronized (mBinder) {
784                if (mHeld) {
785                    try {
786                        mService.releaseWifiLock(mBinder);
787                    } catch (RemoteException ignore) {
788                    }
789                }
790            }
791        }
792    }
793
794    /**
795     * Creates a new WifiLock.
796     *
797     * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL} and
798     * {@link #WIFI_MODE_SCAN_ONLY} for descriptions of the types of Wi-Fi locks.
799     * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
800     *            never shown to the user under normal conditions, but should be descriptive
801     *            enough to identify your application and the specific WifiLock within it, if it
802     *            holds multiple WifiLocks.
803     *
804     * @return a new, unacquired WifiLock with the given tag.
805     *
806     * @see WifiLock
807     */
808    public WifiLock createWifiLock(int lockType, String tag) {
809        return new WifiLock(lockType, tag);
810    }
811
812    /**
813     * Creates a new WifiLock.
814     *
815     * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
816     *            never shown to the user under normal conditions, but should be descriptive
817     *            enough to identify your application and the specific WifiLock within it, if it
818     *            holds multiple WifiLocks.
819     *
820     * @return a new, unacquired WifiLock with the given tag.
821     *
822     * @see WifiLock
823     */
824    public WifiLock createWifiLock(String tag) {
825        return new WifiLock(WIFI_MODE_FULL, tag);
826    }
827
828    /**
829     * Check multicast filter status.
830     *
831     * @return true if multicast packets are allowed.
832     *
833     * @hide pending API council approval
834     */
835    public boolean isMulticastEnabled() {
836        try {
837            return mService.isMulticastEnabled();
838        } catch (RemoteException e) {
839            return false;
840        }
841    }
842
843    /**
844     * Turn on the reception of multicast packets.
845     * The default behavior is to disable multicast packets as they
846     * have a noticable negative effect on battery life.  An
847     * application can turn them on, but should not leave it on for longer
848     * than needed.  When the app quits (or crashes) its request will
849     * be reverted.
850     *
851     * @param tag a string associated with this request for debugging.
852     *
853     * @return true on success
854     *
855     * @see #disableMulticast
856     *
857     * @hide pending API council approval
858     */
859    public boolean enableMulticast(String tag) {
860        try {
861            mService.enableMulticast(new Binder(), tag);
862            return true;
863        } catch (RemoteException e) {
864            return false;
865        }
866    }
867
868    /**
869     * Return to the default multicast-off setting.
870     * Note that if others had turned on Multicast reception, your
871     * call will not turn it back off - they must also turn off their
872     * request for multicast reception.
873     *
874     * @return true on success
875     *
876     * @see #enableMulticast
877     *
878     * @hide pending API council approval
879     */
880    public boolean disableMulticast() {
881        try {
882            mService.disableMulticast();
883            return true;
884        } catch (RemoteException e) {
885            return false;
886        }
887    }
888}
889