Projects >> android_frameworks_base >>cc20f3c384d096afe661a0b3ba51e65e721196ce

Chunk
Conflicting content
    /**
     * Check if private DNS route is set for the network
     */
<<<<<<< HEAD
    public boolean isPrivateDnsRouteSet() {
        return mPrivateDnsRouteSet.get();
=======
    void notifyDriverStopped() {
        // Send a driver stopped message to our handler
        Message.obtain(this, EVENT_DRIVER_STATE_CHANGED, DRIVER_STOPPED, 0).sendToTarget();
>>>>>>> ea6bb1b4d7111dfd084f772f83094bda662fdb23
    }

    /**
Solution content
    /**
     * Check if private DNS route is set for the network
     */
    public boolean isPrivateDnsRouteSet() {
        return mPrivateDnsRouteSet.get();
    }

    /**
File
WifiStateTracker.java
Developer's decision
Version 1
Kind of conflict
Comment
Method invocation
Method signature
Return statement
Chunk
Conflicting content
                     */
    }

    /**
    }

    /**
     *
    }

    /**
        }

        @Override
                // Wi-Fi network state changed:
                // [31- 6] Reserved for future use

        }
    }

<<<<<<< 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();
                /* Reset notification state on new connection */
                resetNotificationTimer();
                /*
                 * DHCP requests are blocking, so run them in a separate thread.
                 */
                HandlerThread dhcpThread = new HandlerThread("DHCP Handler Thread");
                } else if (newState != currentState ||
                dhcpThread.start();
                mDhcpTarget = new DhcpHandler(dhcpThread.getLooper(), this);
                mIsScanModeActive = true;
                mIsHighPerfEnabled = false;
                mOptimizationsDisabledRefCount = 0;
                mPowerModeRefCount = 0;
                mTornDownByConnMgr = false;
                mLastBssid = null;
                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;
                }
                    resetSupplicantLoopState();

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

                    mDisconnectExpected = false;
                    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;
                // [ 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();
                }
                break;
            
            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_STOPPED:
                    mRunState = RUN_STATE_STOPPED;
                    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);
        }
    }

    /**
        return WifiNative.loadDriver();
     * 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);
        }
    }

    private void cancelDisconnect() {
        mDisconnectPending = false;
        removeMessages(EVENT_DEFERRED_DISCONNECT);
    }

    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() {
     * 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
     */
     * Initiate a re-association in supplicant
    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);
     * @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.
        public void onChange(boolean selfChange) {
     * @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(); 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; } } >>>>>>> ea6bb1b4d7111dfd084f772f83094bda662fdb23 }

Solution content
        }
    }

}
File
WifiStateTracker.java
Developer's decision
Version 1
Kind of conflict
Annotation
Class declaration
Comment
Method declaration