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