FileDocCategorySizeDatePackage
WifiLayer.javaAPI DocAndroid 1.5 API45683Wed May 06 22:42:48 BST 2009com.android.settings.wifi

WifiLayer

public class WifiLayer extends Object
Helper class for abstracting Wi-Fi.

Client must call {@link #onCreate()}, {@link #onCreatedCallback()}, {@link #onPause()}, {@link #onResume()}.

Fields Summary
private static final String
TAG
static final boolean
LOGV
private android.content.Context
mContext
private Callback
mCallback
static final int
MESSAGE_ATTEMPT_SCAN
private android.os.Handler
mHandler
private android.net.wifi.WifiManager
mWifiManager
private android.content.IntentFilter
mIntentFilter
private List
mApScanList
private List
mApOtherList
private AccessPointState
mCurrentPrimaryAp
private AccessPointState
mLastAuthenticatingAp
The last access point that we were authenticating with.
private static final int
CONTINUOUS_SCAN_DELAY_MS
The delay between scans when we're continually scanning.
private static final int
SCAN_MAX_RETRY
On failure, the maximum retries for scanning.
private static final int
SCAN_RETRY_DELAY_MS
On failure, the delay between each scan retry.
private int
mScanRetryCount
On failure, the number of retries so far.
private boolean
mIsObtainingAddress
Whether we're currently obtaining an address. Continuous scanning will be disabled in this state.
private int
WIFI_NUM_OPEN_NETWORKS_KEPT
See {@link android.provider.Settings.Secure#WIFI_NUM_OPEN_NETWORKS_KEPT}.
private static final int
HIGHEST_PRIORITY_MAX_VALUE
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 int
mNextHighestPriority
Never access directly, only the related methods should.
private boolean
mReenableApsOnNetworkStateChange
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 android.net.wifi.SupplicantState
mCurrentSupplicantState
The current supplicant state, as broadcasted.
private android.content.BroadcastReceiver
mReceiver
private static final int
ADD_CONFIGURATION_ENABLE
private static final int
ADD_CONFIGURATION_SAVE
Constructors Summary
public WifiLayer(android.content.Context context, Callback callback)
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.

    
                                                               
         
        mContext = context;
        mCallback = callback;
    
Methods Summary
private android.net.wifi.WifiConfigurationaddConfiguration(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 voidattemptReenableAllAps()

        if (mReenableApsOnNetworkStateChange) {
            mReenableApsOnNetworkStateChange = false;
            enableAllAps();
        }
    
public voidattemptScan()
Attempts to scan networks. This has a retry mechanism.

        
        // Remove any future scans since we're scanning right now
        removeFutureScans();
        
        if (!mWifiManager.isWifiEnabled()) return;
        
        if (!mWifiManager.startScan()) {
            postAttemptScan();
        } else {
            mScanRetryCount = 0;
        }
    
private voidcheckForExcessOpenNetworks()
Checks if there are too many open networks, and removes the excess ones.

        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 voidcheckNextHighestPriority(int priority)
Makes sure the next highest priority is larger than the given 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;
        }
    
private voidclearApLists()

        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));
        }
    
public booleanconnectToNetwork(AccessPointState state)
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.

        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;
    
private voidenableAllAps()

        synchronized(this) {
            if (LOGV) {
                Log.v(TAG, " Enabling all APs");
            }
            
            enableApsLocked(mApOtherList);
            enableApsLocked(mApScanList);
        }
    
private voidenableApsLocked(java.util.List 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 voidensureTrackingState(AccessPointState state)
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.

        synchronized (this) {
            if (hasApInstanceLocked(state)) {
                return;
            }
            
            mApOtherList.add(state);
        }
    
public voiderror(int messageResId)

        Log.e(TAG, mContext.getResources().getString(messageResId));
        
        if (mCallback != null) {
            mCallback.onError(messageResId);
        }
    
private static AccessPointStatefindApLocked(java.util.List list, int networkId, java.lang.String bssid, java.lang.String ssid, java.lang.String security)
Must call while holding the lock for the list, which is usually the WifiLayer instance.

        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;
    
private AccessPointStatefindApLocked(int networkId, java.lang.String bssid, java.lang.String ssid, java.lang.String security)
Must call while holding the lock for the lists, which is usually this WifiLayer instance.

        AccessPointState ap = findApLocked(mApScanList, networkId, bssid, ssid, security);
        if (ap == null) {
            ap = findApLocked(mApOtherList, networkId, bssid, ssid, security);
        }
        return ap;
    
private android.net.wifi.WifiConfigurationfindConfiguredNetwork(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;
    
public booleanforgetNetwork(AccessPointState state)
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.

        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;
    
private java.util.ArrayListgetApsSortedByPriorityLocked()

        // 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;
    
private java.util.ListgetConfiguredNetworks()

        final List<WifiConfiguration> wifiConfigs = mWifiManager.getConfiguredNetworks();
        return wifiConfigs;
    
private AccessPointStategetCurrentAp()

        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 intgetNextHighestPriority()
Gets the next highest priority. If this value is larger than the max, shift all the priorities so the lowest starts at 0.

Only {@link #setHighestPriorityStateAndSave(AccessPointState, WifiConfiguration)} should call this.

return
The next highest priority to use.

        if (mNextHighestPriority > HIGHEST_PRIORITY_MAX_VALUE) {
            shiftPriorities();
        }
        
        return mNextHighestPriority++;
    
public AccessPointStategetWifiLayerApInstance(AccessPointState state)
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.

        synchronized (this) {
            
            if (hasApInstanceLocked(state)) {
                return state;
            }
            
            return findApLocked(state.networkId, state.bssid, state.ssid, state.security);
        }
    
private voidhandleDisablingScanWhileObtainingAddress(android.net.NetworkInfo.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 voidhandleNetworkIdsChanged()

        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 voidhandleNetworkStateChanged(android.net.NetworkInfo info, java.lang.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 voidhandleScanResultsAvailable()

        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 voidhandleSignalChanged(int rssi)

        
        if (mCurrentPrimaryAp != null) {
            mCurrentPrimaryAp.setSignal(rssi);
        }
    
private voidhandleSupplicantConnectionChanged(boolean connected)

        if (mCallback != null) {
            mCallback.onAccessPointsStateChanged(connected);
        }
        
        if (connected) {
            refreshAll(true);
        }
    
private voidhandleSupplicantStateChanged(android.net.wifi.SupplicantState state, boolean hasError, int error)

        mCurrentSupplicantState = state;
        
        if (SupplicantState.FOUR_WAY_HANDSHAKE.equals(state)) {
            mLastAuthenticatingAp = getCurrentAp();
        }
        
        if (hasError) {
            handleSupplicantStateError(error);
        }
    
private voidhandleSupplicantStateError(int supplicantError)

        if (supplicantError == WifiManager.ERROR_AUTHENTICATING) {
            if (mCallback != null) {
                if (mLastAuthenticatingAp != null) {
                    mCallback.onRetryPassword(mLastAuthenticatingAp);
                }
            }
        }
    
private voidhandleWifiStateChanged(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 booleanhasApInstanceLocked(AccessPointState state)
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.

Must call while holding the lock for the lists, which is usually this WifiLayer instance.

        
        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 booleanisConsideredForHighestPriority(AccessPointState state)

        return state.configured && state.networkId != AccessPointState.NETWORK_ID_ANY &&
                state.networkId != AccessPointState.NETWORK_ID_NOT_SET;
    
public booleanisWifiEnabled()

        return mWifiManager.isWifiEnabled();
    
private voidloadConfiguredAccessPoints()

        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 booleanmanagerEnableNetwork(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 booleanmanagerSaveConfiguration()

        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;
    
public voidonCreate()
The client MUST call this.

This shouldn't have any dependency on the callback.

        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);
    
public voidonCreatedCallback()
The client MUST call this.

Callback is ready, this can do whatever it wants with it.

        if (isWifiEnabled()) {
            refreshAll(false);
        }
    
public voidonPause()
The client MUST call this.

see
android.app.Activity#onPause

        mContext.unregisterReceiver(mReceiver);
        
        attemptReenableAllAps();
        
        removeFutureScans();
    
public voidonResume()
The client MUST call this.

see
android.app.Activity#onResume

        mContext.registerReceiver(mReceiver, mIntentFilter);
        
        if (isWifiEnabled()) {
            // Kick start the continual scan
            queueContinuousScan();
        }
    
private voidonScanningEnded()

        queueContinuousScan();
        
        if (mCallback != null) {
            mCallback.onScanningStatusChanged(false);
        }
    
private voidonScanningStarted()

        if (mCallback != null) {
            mCallback.onScanningStatusChanged(true);
        }
    
private voidpostAttemptScan()

        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 voidqueueContinuousScan()

        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 voidrefreshAll(boolean attemptScan)

        loadConfiguredAccessPoints();
        refreshStatus();
        
        if (attemptScan) {
            attemptScan();
        }
    
private voidrefreshStatus()

        refreshStatus(null, null);
    
private voidrefreshStatus(AccessPointState ap, android.net.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();
        }
    
private voidremoveApFromUi(AccessPointState ap)

        if (mCallback != null) {
            mCallback.onAccessPointSetChanged(ap, false);
        }
    
private voidremoveFutureScans()

        mHandler.removeMessages(MESSAGE_ATTEMPT_SCAN);
    
public booleansaveNetwork(AccessPointState state)
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.

        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;
    
private booleansetHighestPriorityStateAndSave(AccessPointState state, android.net.wifi.WifiConfiguration reusableConfiguration)
Sets the access point state to the highest priority.

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.


        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;
    
private voidsetPrimaryAp(AccessPointState ap)

        synchronized (this) {
            // Unset other
            if (mCurrentPrimaryAp != null) {
                mCurrentPrimaryAp.setPrimary(false);
            }

            mCurrentPrimaryAp = ap;
        }

        if (ap != null) {
            ap.setPrimary(true);
        }
    
private booleanshiftPriorities()
Shift all the priorities so the lowest starts at 0.

return
Whether the operation was successful.

        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;
        }