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