diff options
Diffstat (limited to 'src/com/android/settings/wifi/WifiLayer.java')
-rw-r--r-- | src/com/android/settings/wifi/WifiLayer.java | 1302 |
1 files changed, 0 insertions, 1302 deletions
diff --git a/src/com/android/settings/wifi/WifiLayer.java b/src/com/android/settings/wifi/WifiLayer.java deleted file mode 100644 index b0857d2..0000000 --- a/src/com/android/settings/wifi/WifiLayer.java +++ /dev/null @@ -1,1302 +0,0 @@ -/* - * Copyright (C) 2007 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 com.android.settings.wifi; - -import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; -import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; - -import com.android.settings.R; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.NetworkInfo; -import android.net.NetworkInfo.DetailedState; -import android.net.NetworkInfo.State; -import android.net.wifi.ScanResult; -import android.net.wifi.SupplicantState; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiInfo; -import android.net.wifi.WifiManager; -import android.os.Handler; -import android.os.Message; -import android.provider.Settings; -import android.text.TextUtils; -import android.util.Config; -import android.util.Log; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -/** - * Helper class for abstracting Wi-Fi. - * <p> - * Client must call {@link #onCreate()}, {@link #onCreatedCallback()}, - * {@link #onPause()}, {@link #onResume()}. - */ -public class WifiLayer { - - private static final String TAG = "SettingsWifiLayer"; - static final boolean LOGV = false || Config.LOGV; - - //============================ - // Other member variables - //============================ - - private Context mContext; - private Callback mCallback; - - static final int MESSAGE_ATTEMPT_SCAN = 1; - private Handler mHandler = new MyHandler(); - - //============================ - // Wifi member variables - //============================ - - private WifiManager mWifiManager; - private IntentFilter mIntentFilter; - private List<AccessPointState> mApScanList = new ArrayList<AccessPointState>(); - private List<AccessPointState> mApOtherList = new ArrayList<AccessPointState>(); - private AccessPointState mCurrentPrimaryAp; - - /** The last access point that we were authenticating with. */ - private AccessPointState mLastAuthenticatingAp; - - /** The delay between scans when we're continually scanning. */ - private static final int CONTINUOUS_SCAN_DELAY_MS = 6000; - /** On failure, the maximum retries for scanning. */ - private static final int SCAN_MAX_RETRY = 5; - /** On failure, the delay between each scan retry. */ - private static final int SCAN_RETRY_DELAY_MS = 1000; - /** On failure, the number of retries so far. */ - private int mScanRetryCount = 0; - /** - * Whether we're currently obtaining an address. Continuous scanning will be - * disabled in this state. - */ - private boolean mIsObtainingAddress; - - /** - * See {@link android.provider.Settings.Secure#WIFI_NUM_OPEN_NETWORKS_KEPT}. - */ - private int WIFI_NUM_OPEN_NETWORKS_KEPT; - /** - * Once the highest priority exceeds this value, all networks will be - * wrapped around starting at 0. This is so another client of the Wi-Fi - * API can have access points that aren't managed by us. (If the other - * client wants lower-priority access points than ours, it can use negative - * priority.) - */ - private static final int HIGHEST_PRIORITY_MAX_VALUE = 99999; - /** - * Never access directly, only the related methods should. - */ - private int mNextHighestPriority; - - /** - * This is used to track when the user wants to connect to a specific AP. We - * disable all other APs, set this to true, and let wpa_supplicant connect. - * Once we get a network state change, we re-enable the rest of them. - */ - private boolean mReenableApsOnNetworkStateChange = false; - - /** - * The current supplicant state, as broadcasted. - */ - private SupplicantState mCurrentSupplicantState; - - //============================ - // Inner classes - //============================ - - interface Callback { - void onError(int messageResId); - - /** - * Called when an AP is added or removed. - * - * @param ap The AP. - * @param added {@code true} if added, {@code false} if removed. - */ - void onAccessPointSetChanged(AccessPointState ap, boolean added); - - /** - * Called when the scanning status changes. - * - * @param started {@code true} if the scanning just started, - * {@code false} if it just ended. - */ - void onScanningStatusChanged(boolean started); - - /** - * Called when the access points should be enabled or disabled. This is - * called from both wpa_supplicant being connected/disconnected and Wi-Fi - * being enabled/disabled. - * - * @param enabled {@code true} if they should be enabled, {@code false} - * if they should be disabled. - */ - void onAccessPointsStateChanged(boolean enabled); - - /** - * Called when there is trouble authenticating and the retry-password - * dialog should be shown. - * - * @param ap The access point. - */ - void onRetryPassword(AccessPointState ap); - } - - private BroadcastReceiver mReceiver = new BroadcastReceiver() { - - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { - handleNetworkStateChanged( - (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO), - intent.getStringExtra(WifiManager.EXTRA_BSSID)); - } else if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { - handleScanResultsAvailable(); - } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) { - handleSupplicantConnectionChanged( - intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false)); - } else if (action.equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)) { - handleSupplicantStateChanged( - (SupplicantState) intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE), - intent.hasExtra(WifiManager.EXTRA_SUPPLICANT_ERROR), - intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, 0)); - } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - handleWifiStateChanged(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, - WifiManager.WIFI_STATE_UNKNOWN)); - } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) { - handleSignalChanged(intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, 0)); - } else if (action.equals(WifiManager.NETWORK_IDS_CHANGED_ACTION)) { - handleNetworkIdsChanged(); - } - } - }; - - /** - * If using this class, make sure to call the callbacks of this class, such - * as {@link #onCreate()}, {@link #onCreatedCallback()}, - * {@link #onPause()}, {@link #onResume()}. - * - * @param context The context. - * @param callback The interface that will be invoked when events from this - * class are generated. - */ - public WifiLayer(Context context, Callback callback) { - mContext = context; - mCallback = callback; - } - - //============================ - // Lifecycle - //============================ - - /** - * The client MUST call this. - * <p> - * This shouldn't have any dependency on the callback. - */ - public void onCreate() { - mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); - - mIntentFilter = new IntentFilter(); - mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); - mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); - mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); - mIntentFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION); - - WIFI_NUM_OPEN_NETWORKS_KEPT = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.WIFI_NUM_OPEN_NETWORKS_KEPT, 10); - } - - /** - * The client MUST call this. - * <p> - * Callback is ready, this can do whatever it wants with it. - */ - public void onCreatedCallback() { - if (isWifiEnabled()) { - refreshAll(false); - } - } - - /** - * The client MUST call this. - * - * @see android.app.Activity#onResume - */ - public void onResume() { - mContext.registerReceiver(mReceiver, mIntentFilter); - - if (isWifiEnabled()) { - // Kick start the continual scan - queueContinuousScan(); - } - } - - /** - * The client MUST call this. - * - * @see android.app.Activity#onPause - */ - public void onPause() { - mContext.unregisterReceiver(mReceiver); - - attemptReenableAllAps(); - - removeFutureScans(); - } - - //============================ - // "Public" API - //============================ - - /** - * Returns an AccessPointState instance (that we track locally in WifiLayer) - * for the given state. First, we check if we track the given instance. If - * not, we find an equal AccessPointState instance that we track. - * - * @param state An AccessPointState instance that does not necessarily have - * to be one that this WifiLayer class tracks. For example, it - * could be the result of unparceling. - * @return An AccessPointState instance that this WifiLayer class tracks. - */ - public AccessPointState getWifiLayerApInstance(AccessPointState state) { - synchronized (this) { - - if (hasApInstanceLocked(state)) { - return state; - } - - return findApLocked(state.networkId, state.bssid, state.ssid, state.security); - } - } - - /** - * Connects to the network, and creates the Wi-Fi API config if necessary. - * - * @param state The state of the network to connect to. This MUST be an - * instance that was given to you by this class. If you - * constructed the instance yourself (for example, after - * unparceling it), you should use - * {@link #getWifiLayerApInstance(AccessPointState)}. - * @return Whether the operation was successful. - */ - public boolean connectToNetwork(AccessPointState state) { - if (LOGV) { - Log.v(TAG, "Connecting to " + state); - } - - // Need WifiConfiguration for the AP - WifiConfiguration config = findConfiguredNetwork(state); - - if (LOGV) { - Log.v(TAG, " Found configured network " + config); - } - - if (config == null) { - /* - * Connecting for the first time, need to create it. We will enable - * and save it below (when we set priority). - */ - config = addConfiguration(state, 0); - - if (config == null) { - Log.e(TAG, "Config is still null, even after attempting to add it."); - error(R.string.error_connecting); - return false; - } - - /* - * We could reload the configured networks, but instead just - * shortcut and add this state to our list in memory. - */ - ensureTrackingState(state); - } else { - // Make sure the configuration has the latest from the state - state.updateWifiConfiguration(config); - } - - // Enable this network before we save to storage - if (!managerEnableNetwork(state, false)) { - Log.e(TAG, "Could not enable network ID " + state.networkId); - error(R.string.error_connecting); - return false; - } - - /* - * Give it highest priority, this could cause a network ID change, so do - * it after any modifications to the network we're connecting to - */ - setHighestPriorityStateAndSave(state, config); - - /* - * We force supplicant to connect to this network by disabling the - * others. We do this AFTER we save above so this disabled flag isn't - * persisted. - */ - mReenableApsOnNetworkStateChange = true; - if (!managerEnableNetwork(state, true)) { - Log.e(TAG, "Could not enable network ID " + state.networkId); - error(R.string.error_connecting); - return false; - } - - if (LOGV) { - Log.v(TAG, " Enabled network " + state.networkId); - } - - if (mCurrentSupplicantState == SupplicantState.DISCONNECTED || - mCurrentSupplicantState == SupplicantState.SCANNING) { - mWifiManager.reconnect(); - } - - // Check for too many configured open networks - if (!state.hasSecurity()) { - checkForExcessOpenNetworks(); - } - - return true; - } - - /** - * Saves a network, and creates the Wi-Fi API config if necessary. - * - * @param state The state of the network to save. If you constructed the - * instance yourself (for example, after unparceling it), you - * should use {@link #getWifiLayerApInstance(AccessPointState)}. - * @return Whether the operation was successful. - */ - public boolean saveNetwork(AccessPointState state) { - WifiConfiguration config = findConfiguredNetwork(state); - - if (config == null) { - // if the user is adding a new network, assume that it is hidden - state.setHiddenSsid(true); - - config = addConfiguration(state, ADD_CONFIGURATION_ENABLE); - - if (config == null) { - Log.e(TAG, "Could not save configuration, call to addConfiguration failed."); - error(R.string.error_saving); - return false; - } - - } else { - state.updateWifiConfiguration(config); - if (mWifiManager.updateNetwork(config) == -1) { - Log.e(TAG, "Could not update configuration, call to WifiManager failed."); - error(R.string.error_saving); - return false; - } - } - - // Successfully added network, go ahead and persist - if (!managerSaveConfiguration()) { - Log.e(TAG, "Could not save configuration, call to WifiManager failed."); - error(R.string.error_saving); - return false; - } - - /* - * We could reload the configured networks, but instead just shortcut - * and add this state to our list in memory - */ - ensureTrackingState(state); - - return true; - } - - /** - * Forgets a network. - * - * @param state The state of the network to forget. If you constructed the - * instance yourself (for example, after unparceling it), you - * should use {@link #getWifiLayerApInstance(AccessPointState)}. - * @return Whether the operation was succesful. - */ - public boolean forgetNetwork(AccessPointState state) { - if (!state.configured) { - Log.w(TAG, "Inconsistent state: Forgetting a network that is not configured."); - return true; - } - - int oldNetworkId = state.networkId; - state.forget(); - - if (!state.seen) { - // If it is not seen, it should be removed from the UI - removeApFromUi(state); - } - - synchronized (this) { - mApOtherList.remove(state); - // It should not be removed from the scan list, since if it was - // there that means it's still seen - } - - if (!mWifiManager.removeNetwork(oldNetworkId)) { - Log.e(TAG, "Removing network " + state.ssid + " (network ID " + oldNetworkId + - ") failed."); - return false; - } - - if (!managerSaveConfiguration()) { - error(R.string.error_saving); - return false; - } - - return true; - } - - /** - * This ensures this class is tracking the given state. This means it is in - * our list of access points, either in the scanned list or in the - * remembered list. - * - * @param state The state that will be checked for tracking, and if not - * tracking will be added to the remembered list in memory. - */ - private void ensureTrackingState(AccessPointState state) { - synchronized (this) { - if (hasApInstanceLocked(state)) { - return; - } - - mApOtherList.add(state); - } - } - - /** - * Attempts to scan networks. This has a retry mechanism. - */ - public void attemptScan() { - - // Remove any future scans since we're scanning right now - removeFutureScans(); - - if (!mWifiManager.isWifiEnabled()) return; - - if (!mWifiManager.startScan()) { - postAttemptScan(); - } else { - mScanRetryCount = 0; - } - } - - private void queueContinuousScan() { - mHandler.removeMessages(MESSAGE_ATTEMPT_SCAN); - - if (!mIsObtainingAddress) { - // Don't do continuous scan while in obtaining IP state - mHandler.sendEmptyMessageDelayed(MESSAGE_ATTEMPT_SCAN, CONTINUOUS_SCAN_DELAY_MS); - } - } - - private void removeFutureScans() { - mHandler.removeMessages(MESSAGE_ATTEMPT_SCAN); - } - - public boolean isWifiEnabled() { - return mWifiManager.isWifiEnabled(); - } - - public void error(int messageResId) { - Log.e(TAG, mContext.getResources().getString(messageResId)); - - if (mCallback != null) { - mCallback.onError(messageResId); - } - } - - //============================ - // Wifi logic - //============================ - - private void refreshAll(boolean attemptScan) { - loadConfiguredAccessPoints(); - refreshStatus(); - - if (attemptScan) { - attemptScan(); - } - } - - private void postAttemptScan() { - onScanningStarted(); - - if (++mScanRetryCount < SCAN_MAX_RETRY) { - // Just in case, remove previous ones first - removeFutureScans(); - mHandler.sendEmptyMessageDelayed(MESSAGE_ATTEMPT_SCAN, SCAN_RETRY_DELAY_MS); - } else { - // Show an error once we run out of attempts - error(R.string.error_scanning); - onScanningEnded(); - } - } - - private void onScanningStarted() { - if (mCallback != null) { - mCallback.onScanningStatusChanged(true); - } - } - - private void onScanningEnded() { - queueContinuousScan(); - - if (mCallback != null) { - mCallback.onScanningStatusChanged(false); - } - } - - private void clearApLists() { - List<AccessPointState> accessPoints = new ArrayList<AccessPointState>(); - - synchronized(this) { - // Clear the logic's list of access points - accessPoints.addAll(mApScanList); - accessPoints.addAll(mApOtherList); - mApScanList.clear(); - mApOtherList.clear(); - } - - for (int i = accessPoints.size() - 1; i >= 0; i--) { - removeApFromUi(accessPoints.get(i)); - } - } - - private boolean managerSaveConfiguration() { - boolean retValue = mWifiManager.saveConfiguration(); - - /* - * We need to assume the network IDs have changed, so handle this. Note: - * we also have a receiver on the broadcast intent in case another wifi - * framework client caused the change. In this case, we will handle the - * possible network ID change twice (but it's not too costly). - */ - handleNetworkIdsChanged(); - - return retValue; - } - - private boolean managerEnableNetwork(AccessPointState state, boolean disableOthers) { - if (!mWifiManager.enableNetwork(state.networkId, disableOthers)) { - return false; - } - - // Enabling was successful, make sure the state is not disabled - state.setDisabled(false); - - return true; - } - - private static final int ADD_CONFIGURATION_ENABLE = 1; - private static final int ADD_CONFIGURATION_SAVE = 2; - private WifiConfiguration addConfiguration(AccessPointState state, int flags) { - // Create and add - WifiConfiguration config = new WifiConfiguration(); - - state.updateWifiConfiguration(config); - - final int networkId = mWifiManager.addNetwork(config); - if (networkId == -1) { - return null; - } - - state.setNetworkId(networkId); - state.setConfigured(true); - - // If we should, then enable it, since it comes disabled by default - if ((flags & ADD_CONFIGURATION_ENABLE) != 0 - && !managerEnableNetwork(state, false)) { - return null; - } - - // If we should, then save it - if ((flags & ADD_CONFIGURATION_SAVE) != 0 && !managerSaveConfiguration()) { - return null; - } - - if (mCallback != null) { - mCallback.onAccessPointSetChanged(state, true); - } - - return config; - } - - private WifiConfiguration findConfiguredNetwork(AccessPointState state) { - final List<WifiConfiguration> wifiConfigs = getConfiguredNetworks(); - - for (int i = wifiConfigs.size() - 1; i >= 0; i--) { - final WifiConfiguration wifiConfig = wifiConfigs.get(i); - if (state.matchesWifiConfiguration(wifiConfig) >= AccessPointState.MATCH_WEAK) { - return wifiConfig; - } - } - - return null; - } - - private List<WifiConfiguration> getConfiguredNetworks() { - final List<WifiConfiguration> wifiConfigs = mWifiManager.getConfiguredNetworks(); - return wifiConfigs; - } - - /** - * Must call while holding the lock for the list, which is usually the - * WifiLayer instance. - */ - private static AccessPointState findApLocked(List<AccessPointState> list, int networkId, - String bssid, String ssid, String security) { - AccessPointState ap; - for (int i = list.size() - 1; i >= 0; i--) { - ap = list.get(i); - if (ap.matches(networkId, bssid, ssid, security) >= AccessPointState.MATCH_WEAK) { - return ap; - } - } - - return null; - } - - /** - * Must call while holding the lock for the lists, which is usually this - * WifiLayer instance. - */ - private AccessPointState findApLocked(int networkId, String bssid, String ssid, - String security) { - AccessPointState ap = findApLocked(mApScanList, networkId, bssid, ssid, security); - if (ap == null) { - ap = findApLocked(mApOtherList, networkId, bssid, ssid, security); - } - return ap; - } - - /** - * Returns whether we have the exact instance of the access point state - * given. This is useful in cases where an AccessPointState has been - * parceled by the client and the client is attempting to use it to - * connect/forget/save. - * <p> - * Must call while holding the lock for the lists, which is usually this - * WifiLayer instance. - */ - private boolean hasApInstanceLocked(AccessPointState state) { - - for (int i = mApScanList.size() - 1; i >= 0; i--) { - if (mApScanList.get(i) == state) { - return true; - } - } - - for (int i = mApOtherList.size() - 1; i >= 0; i--) { - if (mApOtherList.get(i) == state) { - return true; - } - } - - return false; - } - - private void loadConfiguredAccessPoints() { - final List<WifiConfiguration> configs = getConfiguredNetworks(); - - for (int i = configs.size() - 1; i >= 0; i--) { - final WifiConfiguration config = configs.get(i); - - AccessPointState ap; - synchronized(this) { - ap = findApLocked(config.networkId, config.BSSID, config.SSID, - AccessPointState.getWifiConfigurationSecurity(config)); - - if (ap != null) { - // We already know about this one - continue; - } - - ap = new AccessPointState(mContext); - ap.updateFromWifiConfiguration(config); - if (LOGV) Log.v(TAG, "Created " + ap + " in loadConfiguredAccessPoints"); - mApOtherList.add(ap); - } - - // Make sure our next highest priority is greater than this - checkNextHighestPriority(ap.priority); - - if (mCallback != null) { - mCallback.onAccessPointSetChanged(ap, true); - } - } - } - - private AccessPointState getCurrentAp() { - final WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); - - String ssid = wifiInfo.getSSID(); - if (ssid != null) { - /* - * We pass null for security since we have a network ID (i.e., it's - * not a wildcard), and rely on it matching. - */ - return findApLocked(wifiInfo.getNetworkId(), wifiInfo.getBSSID(), ssid, null); - } else { - return null; - } - } - - private void setPrimaryAp(AccessPointState ap) { - synchronized (this) { - // Unset other - if (mCurrentPrimaryAp != null) { - mCurrentPrimaryAp.setPrimary(false); - } - - mCurrentPrimaryAp = ap; - } - - if (ap != null) { - ap.setPrimary(true); - } - } - - private void attemptReenableAllAps() { - if (mReenableApsOnNetworkStateChange) { - mReenableApsOnNetworkStateChange = false; - enableAllAps(); - } - } - - private void enableAllAps() { - synchronized(this) { - if (LOGV) { - Log.v(TAG, " Enabling all APs"); - } - - enableApsLocked(mApOtherList); - enableApsLocked(mApScanList); - } - } - - private void enableApsLocked(List<AccessPointState> apList) { - for (int i = apList.size() - 1; i >= 0; i--) { - AccessPointState state = apList.get(i); - int networkId = state.networkId; - if (networkId != AccessPointState.NETWORK_ID_NOT_SET && - networkId != AccessPointState.NETWORK_ID_ANY) { - managerEnableNetwork(state, false); - } - } - } - - private void removeApFromUi(AccessPointState ap) { - if (mCallback != null) { - mCallback.onAccessPointSetChanged(ap, false); - } - } - - /** - * Sets the access point state to the highest priority. - * <p> - * If you have a list of configured networks from WifiManager, you probably - * shouldn't call this until you're done traversing the list. - * - * @param state The state to set as the highest priority. - * @param reusableConfiguration An optional WifiConfiguration that will be - * given to the WifiManager as updated data for the network ID. - * This will be filled with the new priority. - * @return Whether the operation was successful. - */ - private boolean setHighestPriorityStateAndSave(AccessPointState state, - WifiConfiguration reusableConfiguration) { - - if (!isConsideredForHighestPriority(state)) { - Log.e(TAG, - "Could not set highest priority on state because state is not being considered."); - return false; - } - - if (reusableConfiguration == null) { - reusableConfiguration = new WifiConfiguration(); - } - - int oldPriority = reusableConfiguration.priority; - reusableConfiguration.priority = getNextHighestPriority(); - reusableConfiguration.networkId = state.networkId; - - if (mWifiManager.updateNetwork(reusableConfiguration) == -1) { - // Rollback priority - reusableConfiguration.priority = oldPriority; - Log.e(TAG, - "Could not set highest priority on state because updating the supplicant network failed."); - return false; - } - - if (!managerSaveConfiguration()) { - reusableConfiguration.priority = oldPriority; - Log.e(TAG, - "Could not set highest priority on state because saving config failed."); - return false; - } - - state.priority = reusableConfiguration.priority; - - if (LOGV) { - Log.v(TAG, " Set highest priority to " - + state.priority + " from " + oldPriority); - } - - return true; - } - - /** - * Makes sure the next highest priority is larger than the given priority. - */ - private void checkNextHighestPriority(int priority) { - if (priority > HIGHEST_PRIORITY_MAX_VALUE || priority < 0) { - // This is a priority that we aren't managing - return; - } - - if (mNextHighestPriority <= priority) { - mNextHighestPriority = priority + 1; - } - } - - /** - * Checks if there are too many open networks, and removes the excess ones. - */ - private void checkForExcessOpenNetworks() { - synchronized(this) { - ArrayList<AccessPointState> allAps = getApsSortedByPriorityLocked(); - - // Walk from highest to lowest priority - int openConfiguredCount = 0; - for (int i = allAps.size() - 1; i >= 0; i--) { - AccessPointState state = allAps.get(i); - if (state.configured && !state.hasSecurity()) { - openConfiguredCount++; - if (openConfiguredCount > WIFI_NUM_OPEN_NETWORKS_KEPT) { - // Remove this network - forgetNetwork(state); - } - } - } - } - } - - private boolean isConsideredForHighestPriority(AccessPointState state) { - return state.configured && state.networkId != AccessPointState.NETWORK_ID_ANY && - state.networkId != AccessPointState.NETWORK_ID_NOT_SET; - } - - /** - * Gets the next highest priority. If this value is larger than the max, - * shift all the priorities so the lowest starts at 0. - * <p> - * Only - * {@link #setHighestPriorityStateAndSave(AccessPointState, WifiConfiguration)} - * should call this. - * - * @return The next highest priority to use. - */ - private int getNextHighestPriority() { - if (mNextHighestPriority > HIGHEST_PRIORITY_MAX_VALUE) { - shiftPriorities(); - } - - return mNextHighestPriority++; - } - - /** - * Shift all the priorities so the lowest starts at 0. - * - * @return Whether the operation was successful. - */ - private boolean shiftPriorities() { - synchronized(this) { - - ArrayList<AccessPointState> allAps = getApsSortedByPriorityLocked(); - - // Re-usable WifiConfiguration for setting priority - WifiConfiguration updatePriorityConfig = new WifiConfiguration(); - - // Set new priorities - mNextHighestPriority = 0; - int size = allAps.size(); - for (int i = 0; i < size; i++) { - AccessPointState state = allAps.get(i); - - if (!isConsideredForHighestPriority(state)) { - continue; - } - - if (!setHighestPriorityStateAndSave(state, updatePriorityConfig)) { - Log.e(TAG, - "Could not shift priorities because setting the new priority failed."); - return false; - } - } - - return true; - } - } - - private ArrayList<AccessPointState> getApsSortedByPriorityLocked() { - // Get all of the access points we have - ArrayList<AccessPointState> allAps = new ArrayList<AccessPointState>(mApScanList.size() - + mApOtherList.size()); - allAps.addAll(mApScanList); - allAps.addAll(mApOtherList); - - // Sort them based on priority - Collections.sort(allAps, new Comparator<AccessPointState>() { - public int compare(AccessPointState object1, AccessPointState object2) { - return object1.priority - object2.priority; - } - }); - - return allAps; - } - - //============================ - // Status related - //============================ - - private void refreshStatus() { - refreshStatus(null, null); - } - - private void refreshStatus(AccessPointState ap, NetworkInfo.DetailedState detailedState) { - final WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); - if (detailedState == null) { - detailedState = WifiInfo.getDetailedStateOf(wifiInfo.getSupplicantState()); - } - - if (ap == null && WifiStatus.isLiveConnection(detailedState)) { - /* - * We pass null for security since we have a network ID (i.e., it's - * not a wildcard), and rely on it matching. - */ - ap = findApLocked(wifiInfo.getNetworkId(), wifiInfo.getBSSID(), wifiInfo - .getSSID(), null); - } - - if (ap != null) { - ap.blockRefresh(); - - // Let the AP get the latest info from the WifiInfo - ap.updateFromWifiInfo(wifiInfo, detailedState); - - // The detailed state from the Intent has more states than the WifiInfo's detailed - // state can have (for example, DHCP completion). Set the status using - // the Intent's detailed state. - ap.setStatus(detailedState); - ap.unblockRefresh(); - } - } - - //============================ - // Wifi callbacks - //============================ - - private void handleNetworkStateChanged(NetworkInfo info, String bssid) { - final AccessPointState ap = getCurrentAp(); - NetworkInfo.DetailedState detailedState = info.getDetailedState(); - - if (LOGV) { - Log.v(TAG, "State change received " + info.toString() + ", or " - + detailedState + " on " + bssid + " matched to " + ap); - } - - handleDisablingScanWhileObtainingAddress(detailedState); - - // This will update the AP with its new info - refreshStatus(ap, detailedState); - - boolean isDisconnected = info.getState().equals(State.DISCONNECTED); - if (ap != null && info.isConnectedOrConnecting()) { - setPrimaryAp(ap); - - if (LOGV) { - Log.v(TAG, " Updated " + ap + " to be primary"); - } - - } else if (isDisconnected) { - - /* - * When we drop off a network (for example, the router is powered - * down when we were connected), we received a DISCONNECT event - * without a BSSID. We should not have a primary AP anymore. - */ - setPrimaryAp(null); - - if (LOGV) { - Log.v(TAG, " Cleared primary"); - } - - } else if (detailedState.equals(DetailedState.FAILED)) { - - /* - * Doh, failed for whatever reason. Unset the primary AP, but set - * failed status on the AP that failed. - */ - setPrimaryAp(null); - ap.setStatus(DetailedState.FAILED); - - // Bring up error dialog - error(R.string.wifi_generic_connection_error); - - } else if (LOGV) { - Log.v(TAG, " Did not update any AP to primary, could have updated " - + ap + " but we aren't connected or connecting"); - } - - if ((ap != null) && (info.isConnected() - || (detailedState == DetailedState.OBTAINING_IPADDR))) { - /* - * Sometimes the scan results do not contain the AP even though it's - * clearly connected. This may be because we do passive background - * scanning that isn't as 'strong' as active scanning, so even - * though a network is nearby, it won't be seen by the passive - * scanning. If we are connected (or obtaining IP) then we know it - * is seen. - */ - ap.setSeen(true); - } - - attemptReenableAllAps(); - } - - private void handleDisablingScanWhileObtainingAddress(DetailedState detailedState) { - - if (detailedState == DetailedState.OBTAINING_IPADDR) { - mIsObtainingAddress = true; - - // We will not scan while obtaining an IP address - removeFutureScans(); - - } else { - mIsObtainingAddress = false; - - // Start continuous scan - queueContinuousScan(); - } - } - - private void handleScanResultsAvailable() { - synchronized(this) { - // In the end, we'll moved the ones no longer seen into the mApOtherList - List<AccessPointState> oldScanList = mApScanList; - List<AccessPointState> newScanList = - new ArrayList<AccessPointState>(oldScanList.size()); - - List<ScanResult> list = mWifiManager.getScanResults(); - if (list != null) { - for (int i = list.size() - 1; i >= 0; i--) { - final ScanResult scanResult = list.get(i); - - if (LOGV) { -// Log.v(TAG, " " + scanResult); - } - - if (scanResult == null) { - continue; - } - - /* - * Ignore adhoc, enterprise-secured, or hidden networks. - * Hidden networks show up with empty SSID. - */ - if (AccessPointState.isAdhoc(scanResult) - || AccessPointState.isEnterprise(scanResult) - || TextUtils.isEmpty(scanResult.SSID)) { - continue; - } - - final String ssid = AccessPointState.convertToQuotedString(scanResult.SSID); - String security = AccessPointState.getScanResultSecurity(scanResult); - - // See if this AP is part of a group of APs (e.g., any large - // wifi network has many APs, we'll only show one) that we've - // seen in this scan - AccessPointState ap = findApLocked(newScanList, AccessPointState.NETWORK_ID_ANY, - AccessPointState.BSSID_ANY, ssid, security); - - // Yup, we've seen this network. - if (ap != null) { - // Use the better signal - if (WifiManager.compareSignalLevel(scanResult.level, ap.signal) > 0) { - ap.setSignal(scanResult.level); - } - - if (LOGV) { -// Log.v(TAG, " Already seen, continuing.."); - } - - continue; - } - - // Find the AP in either our old scan list, or our non-seen - // configured networks list - ap = findApLocked(AccessPointState.NETWORK_ID_ANY, AccessPointState.BSSID_ANY, - ssid, security); - - if (ap != null) { - // Remove the AP from both (no harm if one doesn't contain it) - oldScanList.remove(ap); - mApOtherList.remove(ap); - } else { - ap = new AccessPointState(mContext); -// if (LOGV) Log.v(TAG, "Created " + ap); - } - - // Give it the latest state - ap.updateFromScanResult(scanResult); - - if (mCallback != null) { - mCallback.onAccessPointSetChanged(ap, true); - } - - newScanList.add(ap); - } - } - - // oldScanList contains the ones no longer seen - List<AccessPointState> otherList = mApOtherList; - for (int i = oldScanList.size() - 1; i >= 0; i--) { - final AccessPointState ap = oldScanList.get(i); - - if (ap.configured) { - - // Keep it around, since it is configured - ap.setSeen(false); - otherList.add(ap); - - } else { - - // Remove it since it is not configured and not seen - removeApFromUi(ap); - } - } - - mApScanList = newScanList; - } - - onScanningEnded(); - } - - private void handleSupplicantConnectionChanged(boolean connected) { - if (mCallback != null) { - mCallback.onAccessPointsStateChanged(connected); - } - - if (connected) { - refreshAll(true); - } - } - - private void handleWifiStateChanged(int wifiState) { - - if (wifiState == WIFI_STATE_ENABLED) { - loadConfiguredAccessPoints(); - attemptScan(); - - } else if (wifiState == WIFI_STATE_DISABLED) { - removeFutureScans(); - if (LOGV) Log.v(TAG, "Clearing AP lists because wifi is disabled"); - clearApLists(); - } - - if (mCallback != null) { - mCallback.onAccessPointsStateChanged(wifiState == WIFI_STATE_ENABLED); - } - } - - private void handleSignalChanged(int rssi) { - - if (mCurrentPrimaryAp != null) { - mCurrentPrimaryAp.setSignal(rssi); - } - } - - private void handleSupplicantStateChanged(SupplicantState state, boolean hasError, int error) { - mCurrentSupplicantState = state; - - if (SupplicantState.FOUR_WAY_HANDSHAKE.equals(state)) { - mLastAuthenticatingAp = getCurrentAp(); - } - - if (hasError) { - handleSupplicantStateError(error); - } - } - - private void handleSupplicantStateError(int supplicantError) { - if (supplicantError == WifiManager.ERROR_AUTHENTICATING) { - if (mCallback != null) { - if (mLastAuthenticatingAp != null) { - mCallback.onRetryPassword(mLastAuthenticatingAp); - } - } - } - } - - private void handleNetworkIdsChanged() { - synchronized (this) { - final List<WifiConfiguration> configs = getConfiguredNetworks(); - - for (int i = configs.size() - 1; i >= 0; i--) { - final WifiConfiguration config = configs.get(i); - - AccessPointState ap; - // Since network IDs have changed, we can't use it to find our previous AP state - ap = findApLocked(AccessPointState.NETWORK_ID_ANY, config.BSSID, config.SSID, - AccessPointState.getWifiConfigurationSecurity(config)); - - if (ap == null) { - continue; - } - - ap.setNetworkId(config.networkId); - } - } - } - - private class MyHandler extends Handler { - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MESSAGE_ATTEMPT_SCAN: - attemptScan(); - break; - } - } - } - -} |