*/
mTornDownByConnMgr = false;
HandlerThread dhcpThread = new HandlerThread("DHCP Handler Thread");
dhcpThread.start();
mDisconnectPending = false;
removeMessages(EVENT_DEFERRED_DISCONNECT);
mLastBssid = null;
break;
}
}
mDhcpTarget = new DhcpHandler(dhcpThread.getLooper(), this);
mIsScanModeActive = true;
mIsHighPerfEnabled = false;
}
mOptimizationsDisabledRefCount = 0;
/**
/* Reset notification state on new connection */
resetNotificationTimer();
/*
*/
mPowerModeRefCount = 0;
*
mDisconnectExpected = false;
}
}
private void cancelDisconnect() {
* DHCP requests are blocking, so run them in a separate thread.
}
}
<<<<<<< HEAD
=======
@Override
public void handleMessage(Message msg) {
Intent intent;
switch (msg.what) {
case EVENT_SUPPLICANT_CONNECTION:
mRunState = RUN_STATE_RUNNING;
String macaddr;
synchronized (this) {
updateBatteryWorkSourceLocked(null);
macaddr = WifiNative.getMacAddressCommand();
}
if (macaddr != null) {
mWifiInfo.setMacAddress(macaddr);
}
checkUseStaticIp();
mLastSsid = null;
mIsAnyNetworkDisabled.set(false);
requestConnectionInfo();
SupplicantState supplState = mWifiInfo.getSupplicantState();
if (LOCAL_LOGD) Log.v(TAG, "Connection to supplicant established, state=" +
supplState);
// Wi-Fi supplicant connection state changed:
// [31- 2] Reserved for future use
// [ 1- 0] Connected to supplicant (1), disconnected from supplicant (0) ,
// or supplicant died (2)
EventLog.writeEvent(EVENTLOG_SUPPLICANT_CONNECTION_STATE_CHANGED, 1);
/*
* The COMPLETED state change from the supplicant may have occurred
* in between polling for supplicant availability, in which case
* we didn't perform a DHCP request to get an IP address.
*/
if (supplState == SupplicantState.COMPLETED) {
mLastBssid = mWifiInfo.getBSSID();
mLastSsid = mWifiInfo.getSSID();
configureInterface();
}
if (ActivityManagerNative.isSystemReady()) {
intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, true);
mContext.sendBroadcast(intent);
}
if (supplState == SupplicantState.COMPLETED && mHaveIpAddress) {
setDetailedState(DetailedState.CONNECTED);
} else {
setDetailedState(WifiInfo.getDetailedStateOf(supplState));
}
/*
* Filter out multicast packets. This saves battery power, since
* the CPU doesn't have to spend time processing packets that
* are going to end up being thrown away.
*/
mWM.initializeMulticastFiltering();
if (mBluetoothA2dp == null) {
mBluetoothA2dp = new BluetoothA2dp(mContext);
}
checkIsBluetoothPlaying();
// initialize this after the supplicant is alive
setNumAllowedChannels();
break;
case EVENT_SUPPLICANT_DISCONNECT:
mRunState = RUN_STATE_STOPPED;
synchronized (this) {
updateBatteryWorkSourceLocked(null);
}
boolean died = mWifiState.get() != WIFI_STATE_DISABLED &&
mWifiState.get() != WIFI_STATE_DISABLING;
if (died) {
if (LOCAL_LOGD) Log.v(TAG, "Supplicant died unexpectedly");
} else {
if (LOCAL_LOGD) Log.v(TAG, "Connection to supplicant lost");
}
// Wi-Fi supplicant connection state changed:
// [31- 2] Reserved for future use
// [ 1- 0] Connected to supplicant (1), disconnected from supplicant (0) ,
// or supplicant died (2)
EventLog.writeEvent(EVENTLOG_SUPPLICANT_CONNECTION_STATE_CHANGED, died ? 2 : 0);
closeSupplicantConnection();
if (died) {
resetConnections(true);
}
// When supplicant dies, kill the DHCP thread
if (mDhcpTarget != null) {
mDhcpTarget.getLooper().quit();
mDhcpTarget = null;
}
mContext.removeStickyBroadcast(new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION));
if (ActivityManagerNative.isSystemReady()) {
intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false);
mContext.sendBroadcast(intent);
}
setDetailedState(DetailedState.DISCONNECTED);
setSupplicantState(SupplicantState.UNINITIALIZED);
mHaveIpAddress = false;
mObtainingIpAddress = false;
if (died) {
mWM.setWifiEnabled(false);
}
break;
case EVENT_MAYBE_START_SCAN_POST_DISCONNECT:
// Only do this if we haven't gotten a new supplicant status since the timer
// started
if (mNumSupplicantStateChanges == msg.arg1) {
scan(false); // do a passive scan
}
break;
case EVENT_SUPPLICANT_STATE_CHANGED:
mNumSupplicantStateChanges++;
SupplicantStateChangeResult supplicantStateResult =
(SupplicantStateChangeResult) msg.obj;
SupplicantState newState = supplicantStateResult.state;
SupplicantState currentState = mWifiInfo.getSupplicantState();
// Wi-Fi supplicant state changed:
// [31- 6] Reserved for future use
// [ 5- 0] Supplicant state ordinal (as defined by SupplicantState)
int eventLogParam = (newState.ordinal() & 0x3f);
EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, eventLogParam);
if (LOCAL_LOGD) Log.v(TAG, "Changing supplicant state: "
+ currentState +
" ==> " + newState);
int networkId = supplicantStateResult.networkId;
/**
* The SupplicantState BSSID value is valid in ASSOCIATING state only.
* The NetworkState BSSID value comes upon a successful connection.
*/
if (supplicantStateResult.state == SupplicantState.ASSOCIATING) {
mLastBssid = supplicantStateResult.BSSID;
}
/*
* If we get disconnect or inactive we need to start our
* watchdog timer to start a scan
*/
if (newState == SupplicantState.DISCONNECTED ||
newState == SupplicantState.INACTIVE) {
sendMessageDelayed(obtainMessage(EVENT_MAYBE_START_SCAN_POST_DISCONNECT,
mNumSupplicantStateChanges, 0), KICKSTART_SCANNING_DELAY_MSECS);
}
/*
* Did we get to DISCONNECTED state due to an
* authentication (password) failure?
*/
boolean failedToAuthenticate = false;
if (newState == SupplicantState.DISCONNECTED) {
failedToAuthenticate = mPasswordKeyMayBeIncorrect;
}
mPasswordKeyMayBeIncorrect = false;
/*
* Keep track of the supplicant state and check if we should
* disable the network
*/
boolean disabledNetwork = false;
if (isSupplicantLooping(newState)) {
if (LOCAL_LOGD) {
Log.v(TAG,
"Stop WPA supplicant loop and disable network");
}
disabledNetwork = wifiManagerDisableNetwork(networkId);
}
if (disabledNetwork) {
/*
* Reset the loop state if we disabled the network
*/
resetSupplicantLoopState();
} else if (newState != currentState ||
(newState == SupplicantState.DISCONNECTED && isDriverStopped())) {
setSupplicantState(newState);
if (newState == SupplicantState.DORMANT) {
DetailedState newDetailedState;
Message reconnectMsg = obtainMessage(EVENT_DEFERRED_RECONNECT, mLastBssid);
if (mIsScanOnly || mRunState == RUN_STATE_STOPPING) {
newDetailedState = DetailedState.IDLE;
} else {
newDetailedState = DetailedState.FAILED;
}
handleDisconnectedState(newDetailedState, true);
/**
* If we were associated with a network (networkId != -1),
* assume we reached this state because of a failed attempt
* to acquire an IP address, and attempt another connection
* and IP address acquisition in RECONNECT_DELAY_MSECS
* milliseconds.
*/
if (mRunState == RUN_STATE_RUNNING && !mIsScanOnly && networkId != -1) {
sendMessageDelayed(reconnectMsg, RECONNECT_DELAY_MSECS);
} else if (mRunState == RUN_STATE_STOPPING) {
stopDriver();
} else if (mRunState == RUN_STATE_STARTING && !mIsScanOnly) {
reconnectCommand();
}
} else if (newState == SupplicantState.DISCONNECTED) {
mHaveIpAddress = false;
if (isDriverStopped() || mDisconnectExpected) {
handleDisconnectedState(DetailedState.DISCONNECTED, true);
} else {
scheduleDisconnect();
}
} else if (newState != SupplicantState.COMPLETED && !mDisconnectPending) {
/**
* Ignore events that don't change the connectivity state,
* such as WPA rekeying operations.
*/
if (!(currentState == SupplicantState.COMPLETED &&
(newState == SupplicantState.ASSOCIATING ||
newState == SupplicantState.ASSOCIATED ||
newState == SupplicantState.FOUR_WAY_HANDSHAKE ||
newState == SupplicantState.GROUP_HANDSHAKE))) {
setDetailedState(WifiInfo.getDetailedStateOf(newState));
}
}
intent = new Intent(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
| Intent.FLAG_RECEIVER_REPLACE_PENDING);
intent.putExtra(WifiManager.EXTRA_NEW_STATE, (Parcelable)newState);
if (failedToAuthenticate) {
if (LOCAL_LOGD) Log.d(TAG, "Failed to authenticate, disabling network " + networkId);
wifiManagerDisableNetwork(networkId);
intent.putExtra(
WifiManager.EXTRA_SUPPLICANT_ERROR,
WifiManager.ERROR_AUTHENTICATING);
}
mContext.sendStickyBroadcast(intent);
}
break;
case EVENT_NETWORK_STATE_CHANGED:
/*
* Each CONNECT or DISCONNECT generates a pair of events.
* One is a supplicant state change event, and the other
* is a network state change event. For connects, the
* supplicant event always arrives first, followed by
* the network state change event. Only the latter event
* has the BSSID, which we are interested in capturing.
* For disconnects, the order is the opposite -- the
* network state change event comes first, followed by
* the supplicant state change event.
*/
NetworkStateChangeResult result =
(NetworkStateChangeResult) msg.obj;
// Wi-Fi network state changed:
// [31- 6] Reserved for future use
// [ 5- 0] Detailed state ordinal (as defined by NetworkInfo.DetailedState)
eventLogParam = (result.state.ordinal() & 0x3f);
EventLog.writeEvent(EVENTLOG_NETWORK_STATE_CHANGED, eventLogParam);
if (LOCAL_LOGD) Log.v(TAG, "New network state is " + result.state);
/*
* If we're in scan-only mode, don't advance the state machine, and
* don't report the state change to clients.
*/
if (mIsScanOnly) {
if (LOCAL_LOGD) Log.v(TAG, "Dropping event in scan-only mode");
break;
}
if (result.state != DetailedState.SCANNING) {
/*
* Reset the scan count since there was a network state
* change. This could be from supplicant trying to associate
* with a network.
*/
mNumScansSinceNetworkStateChange = 0;
}
/*
* If the supplicant sent us a CONNECTED event, we don't
* want to send out an indication of overall network
* connectivity until we have our IP address. If the
* supplicant sent us a DISCONNECTED event, we delay
* sending a notification in case a reconnection to
* the same access point occurs within a short time.
*/
if (result.state == DetailedState.DISCONNECTED) {
if (mWifiInfo.getSupplicantState() != SupplicantState.DORMANT) {
scheduleDisconnect();
}
break;
}
requestConnectionStatus(mWifiInfo);
if (!(result.state == DetailedState.CONNECTED &&
(!mHaveIpAddress || mDisconnectPending))) {
setDetailedState(result.state);
}
if (result.state == DetailedState.CONNECTED) {
/*
* Remove the 'available networks' notification when we
* successfully connect to a network.
*/
setNotificationVisible(false, 0, false, 0);
boolean wasDisconnectPending = mDisconnectPending;
cancelDisconnect();
/*
* The connection is fully configured as far as link-level
* connectivity is concerned, but we may still need to obtain
* an IP address.
*/
if (wasDisconnectPending) {
DetailedState saveState = getNetworkInfo().getDetailedState();
handleDisconnectedState(DetailedState.DISCONNECTED, false);
setDetailedStateInternal(saveState);
}
configureInterface();
mLastBssid = result.BSSID;
mLastSsid = mWifiInfo.getSSID();
mLastNetworkId = result.networkId;
if (mHaveIpAddress) {
setDetailedState(DetailedState.CONNECTED);
} else {
setDetailedState(DetailedState.OBTAINING_IPADDR);
}
}
sendNetworkStateChangeBroadcast(mWifiInfo.getBSSID());
break;
case EVENT_SCAN_RESULTS_AVAILABLE:
if (ActivityManagerNative.isSystemReady()) {
mContext.sendBroadcast(new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
}
sendScanResultsAvailable();
/**
* On receiving the first scan results after connecting to
* the supplicant, switch scan mode over to passive.
*/
setScanMode(false);
break;
case EVENT_POLL_INTERVAL:
if (mWifiInfo.getSupplicantState() != SupplicantState.UNINITIALIZED) {
requestPolledInfo(mWifiInfo, true);
checkPollTimer();
}
case EVENT_DEFERRED_DISCONNECT:
if (mWifiInfo.getSupplicantState() != SupplicantState.UNINITIALIZED) {
handleDisconnectedState(DetailedState.DISCONNECTED, true);
}
break;
case EVENT_DEFERRED_RECONNECT:
/**
* mLastBssid can be null when there is a reconnect
* request on the first BSSID we connect to
*/
String BSSID = (msg.obj != null) ? msg.obj.toString() : null;
/**
* If we've exceeded the maximum number of retries for reconnecting
* to a given network, disable the network
*/
if (mWifiInfo.getSupplicantState() != SupplicantState.UNINITIALIZED) {
if (++mReconnectCount > getMaxDhcpRetries()) {
if (LOCAL_LOGD) {
Log.d(TAG, "Failed reconnect count: " +
mReconnectCount + " Disabling " + BSSID);
}
mWM.disableNetwork(mLastNetworkId);
}
reconnectCommand();
}
break;
case EVENT_INTERFACE_CONFIGURATION_SUCCEEDED:
/**
* Since this event is sent from another thread, it might have been
* sent after we closed our connection to the supplicant in the course
* of disabling Wi-Fi. In that case, we should just ignore the event.
*/
if (mWifiInfo.getSupplicantState() == SupplicantState.UNINITIALIZED) {
break;
}
mReconnectCount = 0;
mHaveIpAddress = true;
mObtainingIpAddress = false;
mWifiInfo.setIpAddress(mDhcpInfo.ipAddress);
mLastSignalLevel = -1; // force update of signal strength
if (mNetworkInfo.getDetailedState() != DetailedState.CONNECTED) {
setDetailedState(DetailedState.CONNECTED);
sendNetworkStateChangeBroadcast(mWifiInfo.getBSSID());
} else {
msg = mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
msg.sendToTarget();
}
if (LOCAL_LOGD) Log.v(TAG, "IP configuration: " + mDhcpInfo);
// Wi-Fi interface configuration state changed:
// [31- 1] Reserved for future use
// [ 0- 0] Interface configuration succeeded (1) or failed (0)
EventLog.writeEvent(EVENTLOG_INTERFACE_CONFIGURATION_STATE_CHANGED, 1);
// We've connected successfully, so allow the notification again in the future
resetNotificationTimer();
break;
case EVENT_INTERFACE_CONFIGURATION_FAILED:
if (mWifiInfo.getSupplicantState() != SupplicantState.UNINITIALIZED) {
// Wi-Fi interface configuration state changed:
// [31- 1] Reserved for future use
// [ 0- 0] Interface configuration succeeded (1) or failed (0)
EventLog.writeEvent(EVENTLOG_INTERFACE_CONFIGURATION_STATE_CHANGED, 0);
mHaveIpAddress = false;
mWifiInfo.setIpAddress(0);
mObtainingIpAddress = false;
disconnect();
}
break;
case EVENT_DRIVER_STATE_CHANGED:
// Wi-Fi driver state changed:
// 0 STARTED
// 1 STOPPED
// 2 HUNG
EventLog.writeEvent(EVENTLOG_DRIVER_STATE_CHANGED, msg.arg1);
switch (msg.arg1) {
case DRIVER_STARTED:
/**
* Set the number of allowed radio channels according
* to the system setting, since it gets reset by the
* driver upon changing to the STARTED state.
*/
setNumAllowedChannels();
synchronized (this) {
macaddr = WifiNative.getMacAddressCommand();
if (macaddr != null) {
mWifiInfo.setMacAddress(macaddr);
}
mRunState = RUN_STATE_RUNNING;
if (!mIsScanOnly) {
reconnectCommand();
} else {
// In some situations, supplicant needs to be kickstarted to
// start the background scanning
scan(true);
}
}
break;
case DRIVER_HUNG:
Log.e(TAG, "Wifi Driver reports HUNG - reloading.");
/**
* restart the driver - toggle off and on
*/
mWM.setWifiEnabled(false);
mWM.setWifiEnabled(true);
break;
}
synchronized (this) {
updateBatteryWorkSourceLocked(null);
}
break;
case EVENT_PASSWORD_KEY_MAY_BE_INCORRECT:
mPasswordKeyMayBeIncorrect = true;
break;
}
}
private boolean wifiManagerDisableNetwork(int networkId) {
boolean disabledNetwork = false;
if (0 <= networkId) {
disabledNetwork = mWM.disableNetwork(networkId);
if (LOCAL_LOGD) {
if (disabledNetwork) {
Log.v(TAG, "Disabled network: " + networkId);
}
}
}
if (LOCAL_LOGD) {
if (!disabledNetwork) {
Log.e(TAG, "Failed to disable network:" +
" invalid network id: " + networkId);
}
}
return disabledNetwork;
}
private void configureInterface() {
checkPollTimer();
mLastSignalLevel = -1;
if (!mUseStaticIp) {
if (!mHaveIpAddress && !mObtainingIpAddress) {
mObtainingIpAddress = true;
mDhcpTarget.sendEmptyMessage(EVENT_DHCP_START);
}
} else {
int event;
if (NetworkUtils.configureInterface(mInterfaceName, mDhcpInfo)) {
mHaveIpAddress = true;
event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED;
if (LOCAL_LOGD) Log.v(TAG, "Static IP configuration succeeded");
} else {
mHaveIpAddress = false;
event = EVENT_INTERFACE_CONFIGURATION_FAILED;
if (LOCAL_LOGD) Log.v(TAG, "Static IP configuration failed");
}
sendEmptyMessage(event);
}
}
/**
* Reset our IP state and send out broadcasts following a disconnect.
* @param newState the {@code DetailedState} to set. Should be either
* {@code DISCONNECTED} or {@code FAILED}.
* @param disableInterface indicates whether the interface should
* be disabled
*/
private void handleDisconnectedState(DetailedState newState, boolean disableInterface) {
if (mDisconnectPending) {
cancelDisconnect();
}
mDisconnectExpected = false;
resetConnections(disableInterface);
setDetailedState(newState);
sendNetworkStateChangeBroadcast(mLastBssid);
mWifiInfo.setBSSID(null);
mLastBssid = null;
mLastSsid = null;
mDisconnectPending = false;
}
/**
* Resets the Wi-Fi Connections by clearing any state, resetting any sockets
* using the interface, stopping DHCP, and disabling the interface.
*/
public void resetConnections(boolean disableInterface) {
if (LOCAL_LOGD) Log.d(TAG, "Reset connections and stopping DHCP");
mHaveIpAddress = false;
mObtainingIpAddress = false;
mWifiInfo.setIpAddress(0);
/*
* Reset connection depends on both the interface and the IP assigned,
* so it should be done before any chance of the IP being lost.
*/
NetworkUtils.resetConnections(mInterfaceName);
// Stop DHCP
if (mDhcpTarget != null) {
mDhcpTarget.setCancelCallback(true);
mDhcpTarget.removeMessages(EVENT_DHCP_START);
}
if (!NetworkUtils.stopDhcp(mInterfaceName)) {
Log.e(TAG, "Could not stop DHCP");
}
/**
* Interface is re-enabled in the supplicant
* when moving out of ASSOCIATING state
*/
if(disableInterface) {
if (LOCAL_LOGD) Log.d(TAG, "Disabling interface");
NetworkUtils.disableInterface(mInterfaceName);
}
}
/**
* The supplicant is reporting that we are disconnected from the current
* access point. Often, however, a disconnect will be followed very shortly
* by a reconnect to the same access point. Therefore, we delay resetting
* the connection's IP state for a bit.
*/
private void scheduleDisconnect() {
mDisconnectPending = true;
if (!hasMessages(EVENT_DEFERRED_DISCONNECT)) {
sendEmptyMessageDelayed(EVENT_DEFERRED_DISCONNECT, DISCONNECT_DELAY_MSECS);
}
public DhcpInfo getDhcpInfo() {
return mDhcpInfo;
}
public synchronized List getScanResultsList() {
return mScanResults;
}
public synchronized void setScanResultsList(List scanList) {
mScanResults = scanList;
}
/**
* Get status information for the current connection, if any.
* @return a {@link WifiInfo} object containing information about the current connection
*/
public WifiInfo requestConnectionInfo() {
requestConnectionStatus(mWifiInfo);
requestPolledInfo(mWifiInfo, false);
return mWifiInfo;
}
private void requestConnectionStatus(WifiInfo info) {
String reply = status();
if (reply == null) {
return;
}
/*
* Parse the reply from the supplicant to the status command, and update
* local state accordingly. The reply is a series of lines of the form
* "name=value".
*/
String SSID = null;
String BSSID = null;
String suppState = null;
int netId = -1;
String[] lines = reply.split("\n");
for (String line : lines) {
String[] prop = line.split(" *= *", 2);
if (prop.length < 2)
continue;
String name = prop[0];
String value = prop[1];
if (name.equalsIgnoreCase("id"))
netId = Integer.parseInt(value);
else if (name.equalsIgnoreCase("ssid"))
SSID = value;
else if (name.equalsIgnoreCase("bssid"))
BSSID = value;
else if (name.equalsIgnoreCase("wpa_state"))
suppState = value;
}
info.setNetworkId(netId);
info.setSSID(SSID);
info.setBSSID(BSSID);
/*
* We only set the supplicant state if the previous state was
* UNINITIALIZED. This should only happen when we first connect to
* the supplicant. Once we're connected, we should always receive
* an event upon any state change, but in this case, we want to
* make sure any listeners are made aware of the state change.
*/
if (mWifiInfo.getSupplicantState() == SupplicantState.UNINITIALIZED && suppState != null)
setSupplicantState(suppState);
}
/**
* Get the dynamic information that is not reported via events.
* @param info the object into which the information should be captured.
*/
private synchronized void requestPolledInfo(WifiInfo info, boolean polling)
{
int newRssi = (polling ? getRssiApprox() : getRssi());
if (newRssi != -1 && -200 < newRssi && newRssi < 256) { // screen out invalid values
/* some implementations avoid negative values by adding 256
* so we need to adjust for that here.
*/
if (newRssi > 0) newRssi -= 256;
info.setRssi(newRssi);
/*
* Rather then sending the raw RSSI out every time it
* changes, we precalculate the signal level that would
* be displayed in the status bar, and only send the
* broadcast if that much more coarse-grained number
* changes. This cuts down greatly on the number of
* broadcasts, at the cost of not informing others
* interested in RSSI of all the changes in signal
* level.
*/
// TODO: The second arg to the call below needs to be a symbol somewhere, but
// it's actually the size of an array of icons that's private
// to StatusBar Policy.
int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 4);
if (newSignalLevel != mLastSignalLevel) {
sendRssiChangeBroadcast(newRssi);
}
mLastSignalLevel = newSignalLevel;
} else {
info.setRssi(-200);
}
int newLinkSpeed = getLinkSpeed();
if (newLinkSpeed != -1) {
info.setLinkSpeed(newLinkSpeed);
}
}
private void sendRssiChangeBroadcast(final int newRssi) {
if (ActivityManagerNative.isSystemReady()) {
Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
mContext.sendBroadcast(intent);
}
}
private void sendNetworkStateChangeBroadcast(String bssid) {
Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
| Intent.FLAG_RECEIVER_REPLACE_PENDING);
intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo);
if (bssid != null)
intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
mContext.sendStickyBroadcast(intent);
}
/**
* Disable Wi-Fi connectivity by stopping the driver.
*/
public boolean teardown() {
if (!mTornDownByConnMgr) {
if (disconnectAndStop()) {
setTornDownByConnMgr(true);
return true;
} else {
return false;
}
} else {
return true;
}
* Reenable Wi-Fi connectivity by restarting the driver.
*/
public boolean reconnect() {
if (mTornDownByConnMgr) {
if (restart()) {
setTornDownByConnMgr(false);
return true;
} else {
return false;
}
} else {
return true;
}
}
/**
* We want to stop the driver, but if we're connected to a network,
* we first want to disconnect, so that the supplicant is always in
* a known state (DISCONNECTED) when the driver is stopped.
* @return {@code true} if the operation succeeds, which means that the
* disconnect or stop command was initiated.
*/
public synchronized boolean disconnectAndStop() {
boolean ret = true;;
if (mRunState != RUN_STATE_STOPPING && mRunState != RUN_STATE_STOPPED) {
// Take down any open network notifications
setNotificationVisible(false, 0, false, 0);
if (mWifiInfo.getSupplicantState() == SupplicantState.DORMANT) {
ret = stopDriver();
} else {
ret = disconnect();
}
mRunState = RUN_STATE_STOPPING;
}
return ret;
}
public synchronized boolean restart() {
if (isDriverStopped()) {
mRunState = RUN_STATE_STARTING;
resetConnections(true);
return startDriver();
}
return true;
}
public int getWifiState() {
return mWifiState.get();
}
public void setWifiState(int wifiState) {
mWifiState.set(wifiState);
public boolean isAnyNetworkDisabled() {
return mIsAnyNetworkDisabled.get();
}
/**
* The WifiNative interface functions are listed below.
* The only native call that is not synchronized on
* WifiStateTracker is waitForEvent() which waits on a
* seperate monitor channel.
*
* All supplicant commands need the wifi to be in an
* enabled state. This can be done by checking the
* mWifiState to be WIFI_STATE_ENABLED.
*
* All commands that can cause commands to driver
* initiated need the driver state to be started.
* This is done by checking isDriverStopped() to
* be false.
*/
/**
* Load the driver and firmware
*
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean loadDriver() {
return WifiNative.loadDriver();
}
/**
* Unload the driver and firmware
*
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean unloadDriver() {
return WifiNative.unloadDriver();
}
/**
* Check the supplicant config and
* start the supplicant daemon
*
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean startSupplicant() {
return WifiNative.startSupplicant();
}
/**
* Stop the supplicant daemon
*
* @return {@code true} if the operation succeeds, {@code false} otherwise
public synchronized boolean stopSupplicant() {
return WifiNative.stopSupplicant();
}
/**
* Establishes two channels - control channel for commands
* and monitor channel for notifying WifiMonitor
*
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean connectToSupplicant() {
return WifiNative.connectToSupplicant();
}
/**
* Close the control/monitor channels to supplicant
*/
public synchronized void closeSupplicantConnection() {
WifiNative.closeSupplicantConnection();
}
/**
* Check if the supplicant is alive
*
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean ping() {
if (mWifiState.get() != WIFI_STATE_ENABLED) {
return false;
}
return WifiNative.pingCommand();
}
/**
* initiate an active or passive scan
*
* @param forceActive true if it is a active scan
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean scan(boolean forceActive) {
if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
return false;
}
return WifiNative.scanCommand(forceActive);
}
/**
* Specifies whether the supplicant or driver
* take care of initiating scan and doing AP selection
*
* @param mode
* SUPPL_SCAN_HANDLING_NORMAL
* SUPPL_SCAN_HANDLING_LIST_ONLY
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean setScanResultHandling(int mode) {
if (mWifiState.get() != WIFI_STATE_ENABLED) {
return false;
}
return WifiNative.setScanResultHandlingCommand(mode);
}
/**
* Fetch the scan results from the supplicant
*
* @return example result string
* 00:bb:cc:dd:cc:ee 2427 166 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net1
* 00:bb:cc:dd:cc:ff 2412 165 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net2
*/
public synchronized String scanResults() {
if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
return null;
}
return WifiNative.scanResultsCommand();
}
/**
* Set the scan mode - active or passive
*
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean setScanMode(boolean isScanModeActive) {
if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
return false;
}
if (mIsScanModeActive != isScanModeActive) {
return WifiNative.setScanModeCommand(mIsScanModeActive = isScanModeActive);
}
return true;
}
/**
* Disconnect from Access Point
*
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean disconnect() {
if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
return false;
}
return WifiNative.disconnectCommand();
}
/**
* Initiate a reconnection to AP
*
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean reconnectCommand() {
if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
return false;
}
return WifiNative.reconnectCommand();
}
/**
* Add a network
*
* @return network id of the new network
*/
public synchronized int addNetwork() {
if (mWifiState.get() != WIFI_STATE_ENABLED) {
return -1;
}
return WifiNative.addNetworkCommand();
}
/**
* Delete a network
*
* @param networkId id of the network to be removed
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean removeNetwork(int networkId) {
if (mWifiState.get() != WIFI_STATE_ENABLED) {
return false;
}
return mDisconnectExpected = WifiNative.removeNetworkCommand(networkId);
}
/**
* Enable a network
*
* @param netId network id of the network
* @param disableOthers true, if all other networks have to be disabled
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean enableNetwork(int netId, boolean disableOthers) {
if (mWifiState.get() != WIFI_STATE_ENABLED) {
return false;
}
if (disableOthers) mIsAnyNetworkDisabled.set(true);
return WifiNative.enableNetworkCommand(netId, disableOthers);
}
/**
* Enable all networks
*
* @param networks list of configured networks
*/
public synchronized void enableAllNetworks(List networks) {
if (mWifiState.get() != WIFI_STATE_ENABLED) {
return;
}
mIsAnyNetworkDisabled.set(false);
for (WifiConfiguration config : networks) {
if (config.status == WifiConfiguration.Status.DISABLED) {
WifiNative.enableNetworkCommand(config.networkId, false);
}
}
}
/**
* Disable a network
*
* @param netId network id of the network
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean disableNetwork(int netId) {
if (mWifiState.get() != WIFI_STATE_ENABLED) {
return false;
}
mIsAnyNetworkDisabled.set(true);
return WifiNative.disableNetworkCommand(netId);
}
/**
* Initiate a re-association in supplicant
*
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean reassociate() {
if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
return false;
}
return WifiNative.reassociateCommand();
}
/**
* Blacklist a BSSID. This will avoid the AP if there are
* alternate APs to connect
*
* @param bssid BSSID of the network
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean addToBlacklist(String bssid) {
if (mWifiState.get() != WIFI_STATE_ENABLED) {
return false;
}
return WifiNative.addToBlacklistCommand(bssid);
}
/**
* Clear the blacklist list
*
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean clearBlacklist() {
if (mWifiState.get() != WIFI_STATE_ENABLED) {
return false;
}
return WifiNative.clearBlacklistCommand();
}
/**
* List all configured networks
*
* @return list of networks or null on failure
*/
public synchronized String listNetworks() {
if (mWifiState.get() != WIFI_STATE_ENABLED) {
return null;
}
return WifiNative.listNetworksCommand();
}
/**
* Get network setting by name
*
* @param netId network id of the network
* @param name network variable key
* @return value corresponding to key
*/
public synchronized String getNetworkVariable(int netId, String name) {
if (mWifiState.get() != WIFI_STATE_ENABLED) {
return null;
}
return WifiNative.getNetworkVariableCommand(netId, name);
}
/**
* Set network setting by name
*
* @param netId network id of the network
* @param name network variable key
* @param value network variable value
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean setNetworkVariable(int netId, String name, String value) {
if (mWifiState.get() != WIFI_STATE_ENABLED) {
return false;
}
return WifiNative.setNetworkVariableCommand(netId, name, value);
}
/**
* Get detailed status of the connection
*
* @return Example status result
* bssid=aa:bb:cc:dd:ee:ff
* ssid=TestNet
* id=3
* pairwise_cipher=NONE
* group_cipher=NONE
* key_mgmt=NONE
* wpa_state=COMPLETED
* ip_address=X.X.X.X
*/
public synchronized String status() {
if (mWifiState.get() != WIFI_STATE_ENABLED) {
return null;
}
return WifiNative.statusCommand();
}
/**
* Get RSSI to currently connected network
*
* @return RSSI value, -1 on failure
*/
public synchronized int getRssi() {
if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
return -1;
}
return WifiNative.getRssiApproxCommand();
}
/**
* Get approx RSSI to currently connected network
*
* @return RSSI value, -1 on failure
*/
public synchronized int getRssiApprox() {
if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
return -1;
}
return WifiNative.getRssiApproxCommand();
}
/**
* Get link speed to currently connected network
*
* @return link speed, -1 on failure
*/
public synchronized int getLinkSpeed() {
if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
return -1;
}
return WifiNative.getLinkSpeedCommand();
}
/**
* Start driver
*
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean startDriver() {
if (mWifiState.get() != WIFI_STATE_ENABLED) {
return false;
}
return WifiNative.startDriverCommand();
}
/**
* Stop driver
*
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean stopDriver() {
/* Driver stop should not happen only when supplicant event
* DRIVER_STOPPED has already been handled */
if (mWifiState.get() != WIFI_STATE_ENABLED || mRunState == RUN_STATE_STOPPED) {
return false;
}
return WifiNative.stopDriverCommand();
}
/**
* Start packet filtering
*
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean startPacketFiltering() {
if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
return false;
}
return WifiNative.startPacketFiltering();
}
/**
* Stop packet filtering
*
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean stopPacketFiltering() {
if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
return false;
}
return WifiNative.stopPacketFiltering();
}
/**
* Get power mode
* @return power mode
*/
public synchronized int getPowerMode() {
if (mWifiState.get() != WIFI_STATE_ENABLED && !isDriverStopped()) {
return -1;
}
return WifiNative.getPowerModeCommand();
}
/**
* Set power mode
* @param mode
* DRIVER_POWER_MODE_AUTO
* DRIVER_POWER_MODE_ACTIVE
*
* Uses reference counting to keep power mode active
* as long as one entity wants power mode to be active.
*
* For example, WifiLock high perf mode can keep power mode active
* or a DHCP session can keep it active. As long as one entity wants
* it enabled, it should stay that way
*
*/
private synchronized void setPowerMode(int mode) {
/* It is good to plumb power mode change
* even if ref count indicates already done
* since we could have a case of previous failure.
*/
switch(mode) {
case DRIVER_POWER_MODE_ACTIVE:
mPowerModeRefCount++;
break;
case DRIVER_POWER_MODE_AUTO:
mPowerModeRefCount--;
if (mPowerModeRefCount > 0) {
return;
} else {
/* Keep refcount from becoming negative */
mPowerModeRefCount = 0;
}
break;
}
if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
return;
}
WifiNative.setPowerModeCommand(mode);
}
/**
* Set the number of allowed radio frequency channels from the system
* setting value, if any.
* @return {@code true} if the operation succeeds, {@code false} otherwise, e.g.,
* the number of channels is invalid.
*/
public synchronized boolean setNumAllowedChannels() {
if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
return false;
}
try {
return setNumAllowedChannels(
Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS));
} catch (Settings.SettingNotFoundException e) {
if (mNumAllowedChannels != 0) {
WifiNative.setNumAllowedChannelsCommand(mNumAllowedChannels);
}
// otherwise, use the driver default
}
return true;
}
/**
* Set the number of radio frequency channels that are allowed to be used
* in the current regulatory domain.
* @param numChannels the number of allowed channels. Must be greater than 0
* and less than or equal to 16.
* @return {@code true} if the operation succeeds, {@code false} otherwise, e.g.,
* {@code numChannels} is outside the valid range.
*/
public synchronized boolean setNumAllowedChannels(int numChannels) {
if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
return false;
}
mNumAllowedChannels = numChannels;
return WifiNative.setNumAllowedChannelsCommand(numChannels);
}
/**
* Get number of allowed channels
*
* @return channel count, -1 on failure
*/
public synchronized int getNumAllowedChannels() {
if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
return -1;
}
return WifiNative.getNumAllowedChannelsCommand();
}
/**
* Set bluetooth coex mode:
*
* @param mode
* BLUETOOTH_COEXISTENCE_MODE_ENABLED
* BLUETOOTH_COEXISTENCE_MODE_DISABLED
* BLUETOOTH_COEXISTENCE_MODE_SENSE
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean setBluetoothCoexistenceMode(int mode) {
if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
return false;
}
return WifiNative.setBluetoothCoexistenceModeCommand(mode);
}
/**
* Enable or disable Bluetooth coexistence scan mode. When this mode is on,
* some of the low-level scan parameters used by the driver are changed to
* reduce interference with A2DP streaming.
*
* @param isBluetoothPlaying whether to enable or disable this mode
*/
public synchronized void setBluetoothScanMode(boolean isBluetoothPlaying) {
if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
return;
}
WifiNative.setBluetoothCoexistenceScanModeCommand(isBluetoothPlaying);
}
/**
* Save configuration on supplicant
*
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean saveConfig() {
if (mWifiState.get() != WIFI_STATE_ENABLED) {
return false;
}
return WifiNative.saveConfigCommand();
}
/**
* Reload the configuration from file
*
* @return {@code true} if the operation succeeds, {@code false} otherwise
*/
public synchronized boolean reloadConfig() {
if (mWifiState.get() != WIFI_STATE_ENABLED) {
return false;
}
return WifiNative.reloadConfigCommand();
}
public boolean setRadio(boolean turnOn) {
return mWM.setWifiEnabled(turnOn);
}
/**
* {@inheritDoc}
* There are currently no Wi-Fi-specific features supported.
* @param feature the name of the feature
* @return {@code -1} indicating failure, always
*/
public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) {
return -1;
}
/**
* {@inheritDoc}
* There are currently no Wi-Fi-specific features supported.
* @param feature the name of the feature
* @return {@code -1} indicating failure, always
*/
public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) {
return -1;
}
@Override
public void interpretScanResultsAvailable() {
// If we shouldn't place a notification on available networks, then
// don't bother doing any of the following
if (!mNotificationEnabled) return;
NetworkInfo networkInfo = getNetworkInfo();
State state = networkInfo.getState();
if ((state == NetworkInfo.State.DISCONNECTED)
|| (state == NetworkInfo.State.UNKNOWN)) {
// Look for an open network
List scanResults = getScanResultsList();
if (scanResults != null) {
int numOpenNetworks = 0;
for (int i = scanResults.size() - 1; i >= 0; i--) {
ScanResult scanResult = scanResults.get(i);
if (TextUtils.isEmpty(scanResult.capabilities)) {
numOpenNetworks++;
}
}
if (numOpenNetworks > 0) {
if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) {
/*
* We've scanned continuously at least
* NUM_SCANS_BEFORE_NOTIFICATION times. The user
* probably does not have a remembered network in range,
* since otherwise supplicant would have tried to
* associate and thus resetting this counter.
*/
setNotificationVisible(true, numOpenNetworks, false, 0);
}
return;
}
}
}
// No open networks in range, remove the notification
setNotificationVisible(false, 0, false, 0);
}
/**
* Display or don't display a notification that there are open Wi-Fi networks.
* @param visible {@code true} if notification should be visible, {@code false} otherwise
* @param numNetworks the number networks seen
* @param force {@code true} to force notification to be shown/not-shown,
* even if it is already shown/not-shown.
* @param delay time in milliseconds after which the notification should be made
* visible or invisible.
*/
public void setNotificationVisible(boolean visible, int numNetworks, boolean force, int delay) {
// Since we use auto cancel on the notification, when the
// mNetworksAvailableNotificationShown is true, the notification may
// have actually been canceled. However, when it is false we know
// for sure that it is not being shown (it will not be shown any other
// place than here)
// If it should be hidden and it is already hidden, then noop
if (!visible && !mNotificationShown && !force) {
return;
}
Message message;
if (visible) {
// Not enough time has passed to show the notification again
if (System.currentTimeMillis() < mNotificationRepeatTime) {
return;
}
if (mNotification == null) {
// Cache the Notification mainly so we can remove the
// EVENT_NOTIFICATION_CHANGED message with this Notification from
// the queue later
mNotification = new Notification();
mNotification.when = 0;
mNotification.icon = ICON_NETWORKS_AVAILABLE;
mNotification.flags = Notification.FLAG_AUTO_CANCEL;
mNotification.contentIntent = PendingIntent.getActivity(mContext, 0,
new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK), 0);
}
CharSequence title = mContext.getResources().getQuantityText(
com.android.internal.R.plurals.wifi_available, numNetworks);
CharSequence details = mContext.getResources().getQuantityText(
com.android.internal.R.plurals.wifi_available_detailed, numNetworks);
mNotification.tickerText = title;
mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent);
mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS;
message = mTarget.obtainMessage(EVENT_NOTIFICATION_CHANGED, 1,
ICON_NETWORKS_AVAILABLE, mNotification);
} else {
// Remove any pending messages to show the notification
mTarget.removeMessages(EVENT_NOTIFICATION_CHANGED, mNotification);
message = mTarget.obtainMessage(EVENT_NOTIFICATION_CHANGED, 0, ICON_NETWORKS_AVAILABLE);
}
mTarget.sendMessageDelayed(message, delay);
mNotificationShown = visible;
}
/**
* Clears variables related to tracking whether a notification has been
* shown recently.
*
* After calling this method, the timer that prevents notifications from
* being shown too often will be cleared.
*/
private void resetNotificationTimer() {
mNotificationRepeatTime = 0;
mNumScansSinceNetworkStateChange = 0;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("interface ").append(mInterfaceName);
sb.append(" runState=");
if (mRunState >= 1 && mRunState <= mRunStateNames.length) {
sb.append(mRunStateNames[mRunState-1]);
} else {
sb.append(mRunState);
}
sb.append(LS).append(mWifiInfo).append(LS);
sb.append(mDhcpInfo).append(LS);
sb.append("haveIpAddress=").append(mHaveIpAddress).
append(", obtainingIpAddress=").append(mObtainingIpAddress).
append(", scanModeActive=").append(mIsScanModeActive).append(LS).
append("lastSignalLevel=").append(mLastSignalLevel).
append(", explicitlyDisabled=").append(mTornDownByConnMgr);
return sb.toString();
}
private class DhcpHandler extends Handler {
private Handler mTarget;
/**
* Whether to skip the DHCP result callback to the target. For example,
* this could be set if the network we were requesting an IP for has
* since been disconnected.
* Note: There is still a chance where the client's intended DHCP
* request not being canceled. For example, we are request for IP on
* A, and he queues request for IP on B, and then cancels the request on
* B while we're still requesting from A.
*/
private boolean mCancelCallback;
/**
* Instance of the bluetooth headset helper. This needs to be created
* early because there is a delay before it actually 'connects', as
* noted by its javadoc. If we check before it is connected, it will be
* in an error state and we will not disable coexistence.
*/
private BluetoothHeadset mBluetoothHeadset;
public DhcpHandler(Looper looper, Handler target) {
super(looper);
mTarget = target;
mBluetoothHeadset = new BluetoothHeadset(mContext, null);
}
public void handleMessage(Message msg) {
int event;
switch (msg.what) {
case EVENT_DHCP_START:
boolean modifiedBluetoothCoexistenceMode = false;
int powerMode = DRIVER_POWER_MODE_AUTO;
if (shouldDisableCoexistenceMode()) {
/*
* There are problems setting the Wi-Fi driver's power
* mode to active when bluetooth coexistence mode is
* enabled or sense.
*
* We set Wi-Fi to active mode when
* obtaining an IP address because we've found
* compatibility issues with some routers with low power
* mode.
*
* In order for this active power mode to properly be set,
* we disable coexistence mode until we're done with
* obtaining an IP address. One exception is if we
* are currently connected to a headset, since disabling
* coexistence would interrupt that connection.
*/
modifiedBluetoothCoexistenceMode = true;
// Disable the coexistence mode
setBluetoothCoexistenceMode(
WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
}
powerMode = getPowerMode();
if (powerMode < 0) {
// Handle the case where supplicant driver does not support
// getPowerModeCommand.
powerMode = DRIVER_POWER_MODE_AUTO;
}
if (powerMode != DRIVER_POWER_MODE_ACTIVE) {
setPowerMode(DRIVER_POWER_MODE_ACTIVE);
}
synchronized (this) {
// A new request is being made, so assume we will callback
mCancelCallback = false;
}
Log.d(TAG, "DhcpHandler: DHCP request started");
if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) {
event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED;
if (LOCAL_LOGD) Log.v(TAG, "DhcpHandler: DHCP request succeeded");
} else {
event = EVENT_INTERFACE_CONFIGURATION_FAILED;
Log.i(TAG, "DhcpHandler: DHCP request failed: " +
NetworkUtils.getDhcpError());
}
if (powerMode != DRIVER_POWER_MODE_ACTIVE) {
setPowerMode(powerMode);
}
if (modifiedBluetoothCoexistenceMode) {
// Set the coexistence mode back to its default value
setBluetoothCoexistenceMode(
WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
}
synchronized (this) {
if (!mCancelCallback) {
mTarget.sendEmptyMessage(event);
}
}
break;
}
}
public synchronized void setCancelCallback(boolean cancelCallback) {
mCancelCallback = cancelCallback;
}
/**
* Whether to disable coexistence mode while obtaining IP address. This
* logic will return true only if the current bluetooth
* headset/handsfree state is disconnected. This means if it is in an
* error state, we will NOT disable coexistence mode to err on the side
* of safety.
*
* @return Whether to disable coexistence mode.
*/
private boolean shouldDisableCoexistenceMode() {
int state = mBluetoothHeadset.getState(mBluetoothHeadset.getCurrentHeadset());
return state == BluetoothHeadset.STATE_DISCONNECTED;
}
}
private void checkUseStaticIp() {
mUseStaticIp = false;
final ContentResolver cr = mContext.getContentResolver();
try {
if (Settings.System.getInt(cr, Settings.System.WIFI_USE_STATIC_IP) == 0) {
return;
}
} catch (Settings.SettingNotFoundException e) {
return;
}
try {
String addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_IP);
if (addr != null) {
mDhcpInfo.ipAddress = stringToIpAddr(addr);
} else {
return;
}
addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_GATEWAY);
if (addr != null) {
mDhcpInfo.gateway = stringToIpAddr(addr);
} else {
return;
}
addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_NETMASK);
if (addr != null) {
mDhcpInfo.netmask = stringToIpAddr(addr);
} else {
return;
}
addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_DNS1);
if (addr != null) {
mDhcpInfo.dns1 = stringToIpAddr(addr);
} else {
return;
}
addr = Settings.System.getString(cr, Settings.System.WIFI_STATIC_DNS2);
if (addr != null) {
mDhcpInfo.dns2 = stringToIpAddr(addr);
} else {
mDhcpInfo.dns2 = 0;
}
} catch (UnknownHostException e) {
return;
}
mUseStaticIp = true;
}
private static int stringToIpAddr(String addrString) throws UnknownHostException {
try {
String[] parts = addrString.split("\\.");
if (parts.length != 4) {
throw new UnknownHostException(addrString);
}
int a = Integer.parseInt(parts[0]) ;
int b = Integer.parseInt(parts[1]) << 8;
int c = Integer.parseInt(parts[2]) << 16;
int d = Integer.parseInt(parts[3]) << 24;
return a | b | c | d;
} catch (NumberFormatException ex) {
throw new UnknownHostException(addrString);
}
}
private int getMaxDhcpRetries() {
return Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT,
DEFAULT_MAX_DHCP_RETRIES);
}
private class SettingsObserver extends ContentObserver {
public SettingsObserver(Handler handler) {
super(handler);
ContentResolver cr = mContext.getContentResolver();
cr.registerContentObserver(Settings.System.getUriFor(
Settings.System.WIFI_USE_STATIC_IP), false, this);
cr.registerContentObserver(Settings.System.getUriFor(
Settings.System.WIFI_STATIC_IP), false, this);
cr.registerContentObserver(Settings.System.getUriFor(
Settings.System.WIFI_STATIC_GATEWAY), false, this);
cr.registerContentObserver(Settings.System.getUriFor(
Settings.System.WIFI_STATIC_NETMASK), false, this);
cr.registerContentObserver(Settings.System.getUriFor(
Settings.System.WIFI_STATIC_DNS1), false, this);
cr.registerContentObserver(Settings.System.getUriFor(
Settings.System.WIFI_STATIC_DNS2), false, this);
}
public void onChange(boolean selfChange) {
super.onChange(selfChange);
boolean wasStaticIp = mUseStaticIp;
int oIp, oGw, oMsk, oDns1, oDns2;
oIp = oGw = oMsk = oDns1 = oDns2 = 0;
if (wasStaticIp) {
oIp = mDhcpInfo.ipAddress;
oGw = mDhcpInfo.gateway;
oMsk = mDhcpInfo.netmask;
oDns1 = mDhcpInfo.dns1;
oDns2 = mDhcpInfo.dns2;
}
checkUseStaticIp();
if (mWifiInfo.getSupplicantState() == SupplicantState.UNINITIALIZED) {
return;
}
boolean changed =
(wasStaticIp != mUseStaticIp) ||
(wasStaticIp && (
oIp != mDhcpInfo.ipAddress ||
oGw != mDhcpInfo.gateway ||
oMsk != mDhcpInfo.netmask ||
oDns1 != mDhcpInfo.dns1 ||
oDns2 != mDhcpInfo.dns2));
if (changed) {
resetConnections(true);
configureInterface();
if (mUseStaticIp) {
Message msg = mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
msg.sendToTarget();
}
}
}
}
private class NotificationEnabledSettingObserver extends ContentObserver {
public NotificationEnabledSettingObserver(Handler handler) {
super(handler);
}
public void register() {
ContentResolver cr = mContext.getContentResolver();
cr.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this);
mNotificationEnabled = getValue();
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
mNotificationEnabled = getValue();
if (!mNotificationEnabled) {
// Remove any notification that may be showing
setNotificationVisible(false, 0, true, 0);
}
resetNotificationTimer();
}
private boolean getValue() {
return Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1;
}
>>>>>>> cf66f587514a935c290c8c9558243a48ba0243eb
} |