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