/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.wifi; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.content.Context; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.DhcpInfo; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.wifi.ScanSettings; import android.net.wifi.WifiChannel; import android.os.Binder; import android.os.Build; import android.os.IBinder; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.WorkSource; import android.os.Messenger; import android.util.Log; import android.util.SparseArray; import java.net.InetAddress; import java.util.concurrent.CountDownLatch; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; import java.util.List; /** * This class provides the primary API for managing all aspects of Wi-Fi * connectivity. Get an instance of this class by calling * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.WIFI_SERVICE)}. * It deals with several categories of items: *
Notification of the result of this activity is posted using the
* {@link android.app.Activity#onActivityResult} callback. The
* resultCode
* will be {@link android.app.Activity#RESULT_OK} if scan always mode has
* been turned on or {@link android.app.Activity#RESULT_CANCELED} if the user
* has rejected the request or an error has occurred.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE =
"android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
/**
* Activity Action: Pick a Wi-Fi network to connect to.
*
Input: Nothing. *
Output: Nothing. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK"; /** * In this Wi-Fi lock mode, Wi-Fi will be kept active, * and will behave normally, i.e., it will attempt to automatically * establish a connection to a remembered access point that is * within range, and will do periodic scans if there are remembered * access points but none are in range. */ public static final int WIFI_MODE_FULL = 1; /** * In this Wi-Fi lock mode, Wi-Fi will be kept active, * but the only operation that will be supported is initiation of * scans, and the subsequent reporting of scan results. No attempts * will be made to automatically connect to remembered access points, * nor will periodic scans be automatically performed looking for * remembered access points. Scans must be explicitly requested by * an application in this mode. */ public static final int WIFI_MODE_SCAN_ONLY = 2; /** * In this Wi-Fi lock mode, Wi-Fi will be kept active as in mode * {@link #WIFI_MODE_FULL} but it operates at high performance * with minimum packet loss and low packet latency even when * the device screen is off. This mode will consume more power * and hence should be used only when there is a need for such * an active connection. *
* An example use case is when a voice connection needs to be * kept active even after the device screen goes off. Holding the * regular {@link #WIFI_MODE_FULL} lock will keep the wifi * connection active, but the connection can be lossy. * Holding a {@link #WIFI_MODE_FULL_HIGH_PERF} lock for the * duration of the voice call will improve the call quality. *
* When there is no support from the hardware, this lock mode * will have the same behavior as {@link #WIFI_MODE_FULL} */ public static final int WIFI_MODE_FULL_HIGH_PERF = 3; /** Anything worse than or equal to this will show 0 bars. */ private static final int MIN_RSSI = -100; /** Anything better than or equal to this will show the max bars. */ private static final int MAX_RSSI = -55; /** * Number of RSSI levels used in the framework to initiate * {@link #RSSI_CHANGED_ACTION} broadcast * @hide */ public static final int RSSI_LEVELS = 5; /** * Auto settings in the driver. The driver could choose to operate on both * 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band. * @hide */ public static final int WIFI_FREQUENCY_BAND_AUTO = 0; /** * Operation on 5 GHz alone * @hide */ public static final int WIFI_FREQUENCY_BAND_5GHZ = 1; /** * Operation on 2.4 GHz alone * @hide */ public static final int WIFI_FREQUENCY_BAND_2GHZ = 2; /** List of asyncronous notifications * @hide */ public static final int DATA_ACTIVITY_NOTIFICATION = 1; //Lowest bit indicates data reception and the second lowest //bit indicates data transmitted /** @hide */ public static final int DATA_ACTIVITY_NONE = 0x00; /** @hide */ public static final int DATA_ACTIVITY_IN = 0x01; /** @hide */ public static final int DATA_ACTIVITY_OUT = 0x02; /** @hide */ public static final int DATA_ACTIVITY_INOUT = 0x03; /** @hide */ public static final boolean DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED = false; /* Maximum number of active locks we allow. * This limit was added to prevent apps from creating a ridiculous number * of locks and crashing the system by overflowing the global ref table. */ private static final int MAX_ACTIVE_LOCKS = 50; /* Number of currently active WifiLocks and MulticastLocks */ private int mActiveLockCount; private Context mContext; IWifiManager mService; private final int mTargetSdkVersion; private static final int INVALID_KEY = 0; private static int sListenerKey = 1; private static final SparseArray sListenerMap = new SparseArray(); private static final Object sListenerMapLock = new Object(); private static AsyncChannel sAsyncChannel; private static CountDownLatch sConnected; private static ConnectivityManager sCM; private static final Object sThreadRefLock = new Object(); private static int sThreadRefCount; private static HandlerThread sHandlerThread; @GuardedBy("sCM") // TODO: Introduce refcounting and make this a per-process static callback, instead of a // per-WifiManager callback. private PinningNetworkCallback mNetworkCallback; /** * Create a new WifiManager instance. * Applications will almost always want to use * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}. * @param context the application context * @param service the Binder interface * @hide - hide this because it takes in a parameter of type IWifiManager, which * is a system private class. */ public WifiManager(Context context, IWifiManager service) { mContext = context; mService = service; mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion; init(); } /** * Return a list of all the networks configured in the supplicant. * Not all fields of WifiConfiguration are returned. Only the following * fields are filled in: *
null
. The {@code networkId} field
* must be set to the ID of the existing network being updated.
* @return Returns the {@code networkId} of the supplied
* {@code WifiConfiguration} on success.
* disableOthers
is true, then all other configured
* networks are disabled, and an attempt to connect to the selected
* network is initiated. This may result in the asynchronous delivery
* of state change events.
*
* Note: If an application's target SDK version is
* {@link android.os.Build.VERSION_CODES#LOLLIPOP} or newer, network
* communication may not use Wi-Fi even if Wi-Fi is connected; traffic may
* instead be sent through another network, such as cellular data,
* Bluetooth tethering, or Ethernet. For example, traffic will never use a
* Wi-Fi network that does not provide Internet access (e.g. a wireless
* printer), if another network that does offer Internet access (e.g.
* cellular data) is available. Applications that need to ensure that their
* network traffic uses Wi-Fi should use APIs such as
* {@link Network#bindSocket(java.net.Socket)},
* {@link Network#openConnection(java.net.URL)}, or
* {@link ConnectivityManager#bindProcessToNetwork} to do so.
*
* @param netId the ID of the network in the list of configured networks
* @param disableOthers if true, disable all other networks. The way to
* select a particular network to connect to is specify {@code true}
* for this parameter.
* @return {@code true} if the operation succeeded
*/
public boolean enableNetwork(int netId, boolean disableOthers) {
final boolean pin = disableOthers && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
if (pin) {
registerPinningNetworkCallback();
}
boolean success;
try {
success = mService.enableNetwork(netId, disableOthers);
} catch (RemoteException e) {
success = false;
}
if (pin && !success) {
unregisterPinningNetworkCallback();
}
return success;
}
/**
* Disable a configured network. The specified network will not be
* a candidate for associating. This may result in the asynchronous
* delivery of state change events.
* @param netId the ID of the network as returned by {@link #addNetwork}.
* @return {@code true} if the operation succeeded
*/
public boolean disableNetwork(int netId) {
try {
return mService.disableNetwork(netId);
} catch (RemoteException e) {
return false;
}
}
/**
* Disassociate from the currently active access point. This may result
* in the asynchronous delivery of state change events.
* @return {@code true} if the operation succeeded
*/
public boolean disconnect() {
try {
mService.disconnect();
return true;
} catch (RemoteException e) {
return false;
}
}
/**
* Reconnect to the currently active access point, if we are currently
* disconnected. This may result in the asynchronous delivery of state
* change events.
* @return {@code true} if the operation succeeded
*/
public boolean reconnect() {
try {
mService.reconnect();
return true;
} catch (RemoteException e) {
return false;
}
}
/**
* Reconnect to the currently active access point, even if we are already
* connected. This may result in the asynchronous delivery of state
* change events.
* @return {@code true} if the operation succeeded
*/
public boolean reassociate() {
try {
mService.reassociate();
return true;
} catch (RemoteException e) {
return false;
}
}
/**
* Check that the supplicant daemon is responding to requests.
* @return {@code true} if we were able to communicate with the supplicant and
* it returned the expected response to the PING message.
*/
public boolean pingSupplicant() {
if (mService == null)
return false;
try {
return mService.pingSupplicant();
} catch (RemoteException e) {
return false;
}
}
/**
* Get a list of available channels for customized scan.
*
* @see {@link WifiChannel}
*
* @return the channel list, or null if not available
* @hide
*/
public List
* Note: It is possible for this method to change the network IDs of
* existing networks. You should assume the network IDs can be different
* after calling this method.
*
* @return {@code true} if the operation succeeded
*/
public boolean saveConfiguration() {
try {
return mService.saveConfiguration();
} catch (RemoteException e) {
return false;
}
}
/**
* Set the country code.
* @param countryCode country code in ISO 3166 format.
* @param persist {@code true} if this needs to be remembered
*
* @hide
*/
public void setCountryCode(String country, boolean persist) {
try {
mService.setCountryCode(country, persist);
} catch (RemoteException e) { }
}
/**
* get the country code.
* @return the country code in ISO 3166 format.
*
* @hide
*/
public String getCountryCode() {
try {
String country = mService.getCountryCode();
return(country);
} catch (RemoteException e) {
return null;
}
}
/**
* Set the operational frequency band.
* @param band One of
* {@link #WIFI_FREQUENCY_BAND_AUTO},
* {@link #WIFI_FREQUENCY_BAND_5GHZ},
* {@link #WIFI_FREQUENCY_BAND_2GHZ},
* @param persist {@code true} if this needs to be remembered
* @hide
*/
public void setFrequencyBand(int band, boolean persist) {
try {
mService.setFrequencyBand(band, persist);
} catch (RemoteException e) { }
}
/**
* Get the operational frequency band.
* @return One of
* {@link #WIFI_FREQUENCY_BAND_AUTO},
* {@link #WIFI_FREQUENCY_BAND_5GHZ},
* {@link #WIFI_FREQUENCY_BAND_2GHZ} or
* {@code -1} on failure.
* @hide
*/
public int getFrequencyBand() {
try {
return mService.getFrequencyBand();
} catch (RemoteException e) {
return -1;
}
}
/**
* Check if the chipset supports dual frequency band (2.4 GHz and 5 GHz)
* @return {@code true} if supported, {@code false} otherwise.
* @hide
*/
public boolean isDualBandSupported() {
try {
return mService.isDualBandSupported();
} catch (RemoteException e) {
return false;
}
}
/**
* Return the DHCP-assigned addresses from the last successful DHCP request,
* if any.
* @return the DHCP information
*/
public DhcpInfo getDhcpInfo() {
try {
return mService.getDhcpInfo();
} catch (RemoteException e) {
return null;
}
}
/**
* Enable or disable Wi-Fi.
* @param enabled {@code true} to enable, {@code false} to disable.
* @return {@code true} if the operation succeeds (or if the existing state
* is the same as the requested state).
*/
public boolean setWifiEnabled(boolean enabled) {
try {
return mService.setWifiEnabled(enabled);
} catch (RemoteException e) {
return false;
}
}
/**
* Gets the Wi-Fi enabled state.
* @return One of {@link #WIFI_STATE_DISABLED},
* {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED},
* {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN}
* @see #isWifiEnabled()
*/
public int getWifiState() {
try {
return mService.getWifiEnabledState();
} catch (RemoteException e) {
return WIFI_STATE_UNKNOWN;
}
}
/**
* Return whether Wi-Fi is enabled or disabled.
* @return {@code true} if Wi-Fi is enabled
* @see #getWifiState()
*/
public boolean isWifiEnabled() {
return getWifiState() == WIFI_STATE_ENABLED;
}
/**
* Return TX packet counter, for CTS test of WiFi watchdog.
* @param listener is the interface to receive result
*
* @hide for CTS test only
*/
public void getTxPacketCount(TxPacketCountListener listener) {
validateChannel();
sAsyncChannel.sendMessage(RSSI_PKTCNT_FETCH, 0, putListener(listener));
}
/**
* Calculates the level of the signal. This should be used any time a signal
* is being shown.
*
* @param rssi The power of the signal measured in RSSI.
* @param numLevels The number of levels to consider in the calculated
* level.
* @return A level of the signal, given in the range of 0 to numLevels-1
* (both inclusive).
*/
public static int calculateSignalLevel(int rssi, int numLevels) {
if (rssi <= MIN_RSSI) {
return 0;
} else if (rssi >= MAX_RSSI) {
return numLevels - 1;
} else {
float inputRange = (MAX_RSSI - MIN_RSSI);
float outputRange = (numLevels - 1);
return (int)((float)(rssi - MIN_RSSI) * outputRange / inputRange);
}
}
/**
* Compares two signal strengths.
*
* @param rssiA The power of the first signal measured in RSSI.
* @param rssiB The power of the second signal measured in RSSI.
* @return Returns <0 if the first signal is weaker than the second signal,
* 0 if the two signals have the same strength, and >0 if the first
* signal is stronger than the second signal.
*/
public static int compareSignalLevel(int rssiA, int rssiB) {
return rssiA - rssiB;
}
/**
* Start AccessPoint mode with the specified
* configuration. If the radio is already running in
* AP mode, update the new configuration
* Note that starting in access point mode disables station
* mode operation
* @param wifiConfig SSID, security and channel details as
* part of WifiConfiguration
* @return {@code true} if the operation succeeds, {@code false} otherwise
*
* @hide Dont open up yet
*/
public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
try {
mService.setWifiApEnabled(wifiConfig, enabled);
return true;
} catch (RemoteException e) {
return false;
}
}
/**
* Gets the Wi-Fi enabled state.
* @return One of {@link #WIFI_AP_STATE_DISABLED},
* {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
* {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
* @see #isWifiApEnabled()
*
* @hide Dont open yet
*/
public int getWifiApState() {
try {
return mService.getWifiApEnabledState();
} catch (RemoteException e) {
return WIFI_AP_STATE_FAILED;
}
}
/**
* Return whether Wi-Fi AP is enabled or disabled.
* @return {@code true} if Wi-Fi AP is enabled
* @see #getWifiApState()
*
* @hide Dont open yet
*/
public boolean isWifiApEnabled() {
return getWifiApState() == WIFI_AP_STATE_ENABLED;
}
/**
* Gets the Wi-Fi AP Configuration.
* @return AP details in WifiConfiguration
*
* @hide Dont open yet
*/
public WifiConfiguration getWifiApConfiguration() {
try {
return mService.getWifiApConfiguration();
} catch (RemoteException e) {
return null;
}
}
/**
* Builds a WifiConfiguration from Hotspot 2.0 MIME file.
* @return AP details in WifiConfiguration
*
* @hide Dont open yet
*/
public WifiConfiguration buildWifiConfig(String uriString, String mimeType, byte[] data) {
try {
return mService.buildWifiConfig(uriString, mimeType, data);
} catch (RemoteException e) {
return null;
}
}
/**
* Sets the Wi-Fi AP Configuration.
* @return {@code true} if the operation succeeded, {@code false} otherwise
*
* @hide Dont open yet
*/
public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
try {
mService.setWifiApConfiguration(wifiConfig);
return true;
} catch (RemoteException e) {
return false;
}
}
/**
* Start the driver and connect to network.
*
* This function will over-ride WifiLock and device idle status. For example,
* even if the device is idle or there is only a scan-only lock held,
* a start wifi would mean that wifi connection is kept active until
* a stopWifi() is sent.
*
* This API is used by WifiStateTracker
*
* @return {@code true} if the operation succeeds else {@code false}
* @hide
*/
public boolean startWifi() {
try {
mService.startWifi();
return true;
} catch (RemoteException e) {
return false;
}
}
/**
* Disconnect from a network (if any) and stop the driver.
*
* This function will over-ride WifiLock and device idle status. Wi-Fi
* stays inactive until a startWifi() is issued.
*
* This API is used by WifiStateTracker
*
* @return {@code true} if the operation succeeds else {@code false}
* @hide
*/
public boolean stopWifi() {
try {
mService.stopWifi();
return true;
} catch (RemoteException e) {
return false;
}
}
/**
* Add a bssid to the supplicant blacklist
*
* This API is used by WifiWatchdogService
*
* @return {@code true} if the operation succeeds else {@code false}
* @hide
*/
public boolean addToBlacklist(String bssid) {
try {
mService.addToBlacklist(bssid);
return true;
} catch (RemoteException e) {
return false;
}
}
/**
* Clear the supplicant blacklist
*
* This API is used by WifiWatchdogService
*
* @return {@code true} if the operation succeeds else {@code false}
* @hide
*/
public boolean clearBlacklist() {
try {
mService.clearBlacklist();
return true;
} catch (RemoteException e) {
return false;
}
}
/**
* Enable/Disable TDLS on a specific local route.
*
*
* TDLS enables two wireless endpoints to talk to each other directly
* without going through the access point that is managing the local
* network. It saves bandwidth and improves quality of the link.
*
* This API enables/disables the option of using TDLS. If enabled, the
* underlying hardware is free to use TDLS or a hop through the access
* point. If disabled, existing TDLS session is torn down and
* hardware is restricted to use access point for transferring wireless
* packets. Default value for all routes is 'disabled', meaning restricted
* to use access point for transferring packets.
*
* Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or
* could function over a mobile network, if available. A program that needs to download large
* files should hold a WifiLock to ensure that the download will complete, but a program whose
* network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely
* affecting battery life.
*
* Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane
* Mode. They simply keep the radio from turning off when Wi-Fi is already on but the device
* is idle.
*
* Any application using a WifiLock must request the {@code android.permission.WAKE_LOCK}
* permission in an {@code <uses-permission>} element of the application's manifest.
*/
public class WifiLock {
private String mTag;
private final IBinder mBinder;
private int mRefCount;
int mLockType;
private boolean mRefCounted;
private boolean mHeld;
private WorkSource mWorkSource;
private WifiLock(int lockType, String tag) {
mTag = tag;
mLockType = lockType;
mBinder = new Binder();
mRefCount = 0;
mRefCounted = true;
mHeld = false;
}
/**
* Locks the Wi-Fi radio on until {@link #release} is called.
*
* If this WifiLock is reference-counted, each call to {@code acquire} will increment the
* reference count, and the radio will remain locked as long as the reference count is
* above zero.
*
* If this WifiLock is not reference-counted, the first call to {@code acquire} will lock
* the radio, but subsequent calls will be ignored. Only one call to {@link #release}
* will be required, regardless of the number of times that {@code acquire} is called.
*/
public void acquire() {
synchronized (mBinder) {
if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
try {
mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource);
synchronized (WifiManager.this) {
if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
mService.releaseWifiLock(mBinder);
throw new UnsupportedOperationException(
"Exceeded maximum number of wifi locks");
}
mActiveLockCount++;
}
} catch (RemoteException ignore) {
}
mHeld = true;
}
}
}
/**
* Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle.
*
* If this WifiLock is reference-counted, each call to {@code release} will decrement the
* reference count, and the radio will be unlocked only when the reference count reaches
* zero. If the reference count goes below zero (that is, if {@code release} is called
* a greater number of times than {@link #acquire}), an exception is thrown.
*
* If this WifiLock is not reference-counted, the first call to {@code release} (after
* the radio was locked using {@link #acquire}) will unlock the radio, and subsequent
* calls will be ignored.
*/
public void release() {
synchronized (mBinder) {
if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
try {
mService.releaseWifiLock(mBinder);
synchronized (WifiManager.this) {
mActiveLockCount--;
}
} catch (RemoteException ignore) {
}
mHeld = false;
}
if (mRefCount < 0) {
throw new RuntimeException("WifiLock under-locked " + mTag);
}
}
}
/**
* Controls whether this is a reference-counted or non-reference-counted WifiLock.
*
* Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and
* {@link #release}, and only allow the radio to sleep when every call to {@link #acquire}
* has been balanced with a call to {@link #release}. Non-reference-counted WifiLocks
* lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the
* radio whenever {@link #release} is called and it is locked.
*
* @param refCounted true if this WifiLock should keep a reference count
*/
public void setReferenceCounted(boolean refCounted) {
mRefCounted = refCounted;
}
/**
* Checks whether this WifiLock is currently held.
*
* @return true if this WifiLock is held, false otherwise
*/
public boolean isHeld() {
synchronized (mBinder) {
return mHeld;
}
}
public void setWorkSource(WorkSource ws) {
synchronized (mBinder) {
if (ws != null && ws.size() == 0) {
ws = null;
}
boolean changed = true;
if (ws == null) {
mWorkSource = null;
} else {
ws.clearNames();
if (mWorkSource == null) {
changed = mWorkSource != null;
mWorkSource = new WorkSource(ws);
} else {
changed = mWorkSource.diff(ws);
if (changed) {
mWorkSource.set(ws);
}
}
}
if (changed && mHeld) {
try {
mService.updateWifiLockWorkSource(mBinder, mWorkSource);
} catch (RemoteException e) {
}
}
}
}
public String toString() {
String s1, s2, s3;
synchronized (mBinder) {
s1 = Integer.toHexString(System.identityHashCode(this));
s2 = mHeld ? "held; " : "";
if (mRefCounted) {
s3 = "refcounted: refcount = " + mRefCount;
} else {
s3 = "not refcounted";
}
return "WifiLock{ " + s1 + "; " + s2 + s3 + " }";
}
}
@Override
protected void finalize() throws Throwable {
super.finalize();
synchronized (mBinder) {
if (mHeld) {
try {
mService.releaseWifiLock(mBinder);
synchronized (WifiManager.this) {
mActiveLockCount--;
}
} catch (RemoteException ignore) {
}
}
}
}
}
/**
* Creates a new WifiLock.
*
* @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL},
* {@link #WIFI_MODE_FULL_HIGH_PERF} and {@link #WIFI_MODE_SCAN_ONLY} for
* descriptions of the types of Wi-Fi locks.
* @param tag a tag for the WifiLock to identify it in debugging messages. This string is
* never shown to the user under normal conditions, but should be descriptive
* enough to identify your application and the specific WifiLock within it, if it
* holds multiple WifiLocks.
*
* @return a new, unacquired WifiLock with the given tag.
*
* @see WifiLock
*/
public WifiLock createWifiLock(int lockType, String tag) {
return new WifiLock(lockType, tag);
}
/**
* Creates a new WifiLock.
*
* @param tag a tag for the WifiLock to identify it in debugging messages. This string is
* never shown to the user under normal conditions, but should be descriptive
* enough to identify your application and the specific WifiLock within it, if it
* holds multiple WifiLocks.
*
* @return a new, unacquired WifiLock with the given tag.
*
* @see WifiLock
*/
public WifiLock createWifiLock(String tag) {
return new WifiLock(WIFI_MODE_FULL, tag);
}
/**
* Create a new MulticastLock
*
* @param tag a tag for the MulticastLock to identify it in debugging
* messages. This string is never shown to the user under
* normal conditions, but should be descriptive enough to
* identify your application and the specific MulticastLock
* within it, if it holds multiple MulticastLocks.
*
* @return a new, unacquired MulticastLock with the given tag.
*
* @see MulticastLock
*/
public MulticastLock createMulticastLock(String tag) {
return new MulticastLock(tag);
}
/**
* Allows an application to receive Wifi Multicast packets.
* Normally the Wifi stack filters out packets not explicitly
* addressed to this device. Acquring a MulticastLock will
* cause the stack to receive packets addressed to multicast
* addresses. Processing these extra packets can cause a noticable
* battery drain and should be disabled when not needed.
*/
public class MulticastLock {
private String mTag;
private final IBinder mBinder;
private int mRefCount;
private boolean mRefCounted;
private boolean mHeld;
private MulticastLock(String tag) {
mTag = tag;
mBinder = new Binder();
mRefCount = 0;
mRefCounted = true;
mHeld = false;
}
/**
* Locks Wifi Multicast on until {@link #release} is called.
*
* If this MulticastLock is reference-counted each call to
* {@code acquire} will increment the reference count, and the
* wifi interface will receive multicast packets as long as the
* reference count is above zero.
*
* If this MulticastLock is not reference-counted, the first call to
* {@code acquire} will turn on the multicast packets, but subsequent
* calls will be ignored. Only one call to {@link #release} will
* be required, regardless of the number of times that {@code acquire}
* is called.
*
* Note that other applications may also lock Wifi Multicast on.
* Only they can relinquish their lock.
*
* Also note that applications cannot leave Multicast locked on.
* When an app exits or crashes, any Multicast locks will be released.
*/
public void acquire() {
synchronized (mBinder) {
if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
try {
mService.acquireMulticastLock(mBinder, mTag);
synchronized (WifiManager.this) {
if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
mService.releaseMulticastLock();
throw new UnsupportedOperationException(
"Exceeded maximum number of wifi locks");
}
mActiveLockCount++;
}
} catch (RemoteException ignore) {
}
mHeld = true;
}
}
}
/**
* Unlocks Wifi Multicast, restoring the filter of packets
* not addressed specifically to this device and saving power.
*
* If this MulticastLock is reference-counted, each call to
* {@code release} will decrement the reference count, and the
* multicast packets will only stop being received when the reference
* count reaches zero. If the reference count goes below zero (that
* is, if {@code release} is called a greater number of times than
* {@link #acquire}), an exception is thrown.
*
* If this MulticastLock is not reference-counted, the first call to
* {@code release} (after the radio was multicast locked using
* {@link #acquire}) will unlock the multicast, and subsequent calls
* will be ignored.
*
* Note that if any other Wifi Multicast Locks are still outstanding
* this {@code release} call will not have an immediate effect. Only
* when all applications have released all their Multicast Locks will
* the Multicast filter be turned back on.
*
* Also note that when an app exits or crashes all of its Multicast
* Locks will be automatically released.
*/
public void release() {
synchronized (mBinder) {
if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
try {
mService.releaseMulticastLock();
synchronized (WifiManager.this) {
mActiveLockCount--;
}
} catch (RemoteException ignore) {
}
mHeld = false;
}
if (mRefCount < 0) {
throw new RuntimeException("MulticastLock under-locked "
+ mTag);
}
}
}
/**
* Controls whether this is a reference-counted or non-reference-
* counted MulticastLock.
*
* Reference-counted MulticastLocks keep track of the number of calls
* to {@link #acquire} and {@link #release}, and only stop the
* reception of multicast packets when every call to {@link #acquire}
* has been balanced with a call to {@link #release}. Non-reference-
* counted MulticastLocks allow the reception of multicast packets
* whenever {@link #acquire} is called and stop accepting multicast
* packets whenever {@link #release} is called.
*
* @param refCounted true if this MulticastLock should keep a reference
* count
*/
public void setReferenceCounted(boolean refCounted) {
mRefCounted = refCounted;
}
/**
* Checks whether this MulticastLock is currently held.
*
* @return true if this MulticastLock is held, false otherwise
*/
public boolean isHeld() {
synchronized (mBinder) {
return mHeld;
}
}
public String toString() {
String s1, s2, s3;
synchronized (mBinder) {
s1 = Integer.toHexString(System.identityHashCode(this));
s2 = mHeld ? "held; " : "";
if (mRefCounted) {
s3 = "refcounted: refcount = " + mRefCount;
} else {
s3 = "not refcounted";
}
return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }";
}
}
@Override
protected void finalize() throws Throwable {
super.finalize();
setReferenceCounted(false);
release();
}
}
/**
* Check multicast filter status.
*
* @return true if multicast packets are allowed.
*
* @hide pending API council approval
*/
public boolean isMulticastEnabled() {
try {
return mService.isMulticastEnabled();
} catch (RemoteException e) {
return false;
}
}
/**
* Initialize the multicast filtering to 'on'
* @hide no intent to publish
*/
public boolean initializeMulticastFiltering() {
try {
mService.initializeMulticastFiltering();
return true;
} catch (RemoteException e) {
return false;
}
}
protected void finalize() throws Throwable {
try {
synchronized (sThreadRefLock) {
if (--sThreadRefCount == 0 && sAsyncChannel != null) {
sAsyncChannel.disconnect();
}
}
} finally {
super.finalize();
}
}
/**
* Set wifi verbose log. Called from developer settings.
* @hide
*/
public void enableVerboseLogging (int verbose) {
try {
mService.enableVerboseLogging(verbose);
} catch (Exception e) {
//ignore any failure here
Log.e(TAG, "enableVerboseLogging " + e.toString());
}
}
/**
* Get the WiFi verbose logging level.This is used by settings
* to decide what to show within the picker.
* @hide
*/
public int getVerboseLoggingLevel() {
try {
return mService.getVerboseLoggingLevel();
} catch (RemoteException e) {
return 0;
}
}
/**
* Set wifi Aggressive Handover. Called from developer settings.
* @hide
*/
public void enableAggressiveHandover(int enabled) {
try {
mService.enableAggressiveHandover(enabled);
} catch (RemoteException e) {
}
}
/**
* Get the WiFi Handover aggressiveness.This is used by settings
* to decide what to show within the picker.
* @hide
*/
public int getAggressiveHandover() {
try {
return mService.getAggressiveHandover();
} catch (RemoteException e) {
return 0;
}
}
/**
* Set setting for allowing Scans when traffic is ongoing.
* @hide
*/
public void setAllowScansWithTraffic(int enabled) {
try {
mService.setAllowScansWithTraffic(enabled);
} catch (RemoteException e) {
}
}
/**
* Get setting for allowing Scans when traffic is ongoing.
* @hide
*/
public int getAllowScansWithTraffic() {
try {
return mService.getAllowScansWithTraffic();
} catch (RemoteException e) {
return 0;
}
}
/**
* Set setting for allowing Scans when infrastructure is associated
* @hide
*/
public void setAllowScansWhileAssociated(int enabled) {
try {
mService.setAllowScansWhileAssociated(enabled);
} catch (RemoteException e) {
}
}
/**
* Get setting for allowing Scans when infrastructure is associated
* @hide
*/
public int getAllowScansWhileAssociated() {
try {
return mService.getAllowScansWhileAssociated();
} catch (RemoteException e) {
}
return 0;
}
/**
* Resets all wifi manager settings back to factory defaults.
*
* @hide
*/
public void factoryReset() {
try {
mService.factoryReset();
} catch (RemoteException e) {
}
}
/**
* Get Network object of current wifi network
* @return Get Network object of current wifi network
* @hide
*/
public Network getCurrentNetwork() {
try {
return mService.getCurrentNetwork();
} catch (RemoteException e) {
return null;
}
}
/**
* Set setting for enabling autojoin Offload thru Wifi HAL layer
* @hide
*/
public void setHalBasedAutojoinOffload(int enabled) {
try {
mService.setHalBasedAutojoinOffload(enabled);
} catch (RemoteException e) {
}
}
/**
* Get setting for enabling autojoin Offload thru Wifi HAL layer
* @hide
*/
public int getHalBasedAutojoinOffload() {
try {
return mService.getHalBasedAutojoinOffload();
} catch (RemoteException e) {
}
return 0;
}
/**
* Set setting for enabling network switching while wifi is associated
* @hide
*/
public void setAllowNetworkSwitchingWhileAssociated(int enabled) {
try {
mService.setAllowNetworkSwitchingWhileAssociated(enabled);
} catch (RemoteException e) {
}
}
/**
* Get setting for enabling network switching while wifi is associated
* @hide
*/
public int getAllowNetworkSwitchingWhileAssociated() {
try {
return mService.getAllowNetworkSwitchingWhileAssociated();
} catch (RemoteException e) {
}
return 0;
}
}