美文网首页Android开发之WiFi模块
Android-WiFi开发之 Android 5.0 代码解析

Android-WiFi开发之 Android 5.0 代码解析

作者: 迷你小猪 | 来源:发表于2018-06-03 00:03 被阅读54次

    1. 前言:

    • Android 5.0 原生Settings代码路径: android-5.0.0/packages/apps/Settings.
    • 代码架构: 和 4.4 基本相同, 重要的代码块全部集结在 WifiSettings.java 文件中.
    • WifiSettings.java 文件路径: android-5.0.0/packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java

    2. Android 5.0 WiFi 部分的源码解析:

    2.1 WIFI 模块整体的功能结构:

    1. 开启 WiFi.
    2. 关闭 WiFi.
    3. 获取 WiFi 列表.
    4. 持续扫描 WiFi 热点.
    5. 连接网络.
    6. 忘记网络.
    7. 添加网络.
    8. 网络高级设置等.

    2.2 WiFi 整体功能示意图:

    image.png

    2.3 WiFi 操作的函数封装, 见: Android-WiFi开发之 WifiManager

    2.4 由于代码结构和 4.4 版本的十分类似, 故此处不再分析流程和操作函数分析, 贴出源代码, 利于大家学习, 具体如下:

    /*
     * Copyright (C) 2010 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package com.android.settings.wifi;
    
    import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
    import static android.os.UserManager.DISALLOW_CONFIG_WIFI;
    
    import android.app.Activity;
    import android.app.ActivityManager;
    import android.app.Dialog;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.content.SharedPreferences;
    import android.content.res.Resources;
    import android.content.res.TypedArray;
    import android.location.LocationManager;
    import android.net.ConnectivityManager;
    import android.net.NetworkInfo;
    import android.net.NetworkInfo.DetailedState;
    import android.net.NetworkScoreManager;
    import android.net.NetworkScorerAppManager;
    import android.net.NetworkScorerAppManager.NetworkScorerAppData;
    import android.net.wifi.ScanResult;
    import android.net.wifi.WifiConfiguration;
    import android.net.wifi.WifiInfo;
    import android.net.wifi.WifiManager;
    import android.net.wifi.WpsInfo;
    import android.os.Build;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.os.UserHandle;
    import android.preference.Preference;
    import android.preference.PreferenceScreen;
    import android.util.Log;
    import android.view.ContextMenu;
    import android.view.ContextMenu.ContextMenuInfo;
    import android.view.LayoutInflater;
    import android.view.Menu;
    import android.view.MenuInflater;
    import android.view.MenuItem;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.AdapterView.AdapterContextMenuInfo;
    import android.widget.Button;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import com.android.settings.R;
    import com.android.settings.RestrictedSettingsFragment;
    import com.android.settings.SettingsActivity;
    import com.android.settings.search.BaseSearchIndexProvider;
    import com.android.settings.search.Indexable;
    import com.android.settings.search.SearchIndexableRaw;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.List;
    import java.util.concurrent.atomic.AtomicBoolean;
    
    /**
     * Two types of UI are provided here.
     *
     * The first is for "usual Settings", appearing as any other Setup fragment.
     *
     * The second is for Setup Wizard, with a simplified interface that hides the action bar
     * and menus.
     */
    public class WifiSettings extends RestrictedSettingsFragment
            implements DialogInterface.OnClickListener, Indexable  {
    
        private static final String TAG = "WifiSettings";
    
        private static final int REQUEST_ENABLE_WIFI_ASSISTANT = 1;
    
        /* package */ static final int MENU_ID_WPS_PBC = Menu.FIRST;
        private static final int MENU_ID_WPS_PIN = Menu.FIRST + 1;
        private static final int MENU_ID_SAVED_NETWORK = Menu.FIRST + 2;
        /* package */ static final int MENU_ID_ADD_NETWORK = Menu.FIRST + 3;
        private static final int MENU_ID_ADVANCED = Menu.FIRST + 4;
        private static final int MENU_ID_SCAN = Menu.FIRST + 5;
        private static final int MENU_ID_CONNECT = Menu.FIRST + 6;
        private static final int MENU_ID_FORGET = Menu.FIRST + 7;
        private static final int MENU_ID_MODIFY = Menu.FIRST + 8;
        private static final int MENU_ID_WRITE_NFC = Menu.FIRST + 9;
    
        private static final String KEY_ASSISTANT_DISMISS_PLATFORM = "assistant_dismiss_platform";
    
        public static final int WIFI_DIALOG_ID = 1;
        /* package */ static final int WPS_PBC_DIALOG_ID = 2;
        private static final int WPS_PIN_DIALOG_ID = 3;
        private static final int WRITE_NFC_DIALOG_ID = 6;
    
        // Combo scans can take 5-6s to complete - set to 10s.
        private static final int WIFI_RESCAN_INTERVAL_MS = 10 * 1000;
    
        // Instance state keys
        private static final String SAVE_DIALOG_EDIT_MODE = "edit_mode";
        private static final String SAVE_DIALOG_ACCESS_POINT_STATE = "wifi_ap_state";
    
        private static boolean savedNetworksExist;
    
        private final IntentFilter mFilter;
        private final BroadcastReceiver mReceiver;
        private final Scanner mScanner;
    
        /* package */ WifiManager mWifiManager;
        private WifiManager.ActionListener mConnectListener;
        private WifiManager.ActionListener mSaveListener;
        private WifiManager.ActionListener mForgetListener;
    
        private WifiEnabler mWifiEnabler;
        // An access point being editted is stored here.
        private AccessPoint mSelectedAccessPoint;
    
        private DetailedState mLastState;
        private WifiInfo mLastInfo;
    
        private final AtomicBoolean mConnected = new AtomicBoolean(false);
    
        private WifiDialog mDialog;
        private WriteWifiConfigToNfcDialog mWifiToNfcDialog;
    
        private TextView mEmptyView;
    
        // this boolean extra specifies whether to disable the Next button when not connected. Used by
        // account creation outside of setup wizard.
        private static final String EXTRA_ENABLE_NEXT_ON_CONNECT = "wifi_enable_next_on_connect";
    
        // should Next button only be enabled when we have a connection?
        private boolean mEnableNextOnConnection;
    
        // Save the dialog details
        private boolean mDlgEdit;
        private AccessPoint mDlgAccessPoint;
        private Bundle mAccessPointSavedState;
        private View mWifiAssistantCard;
        private NetworkScorerAppData mWifiAssistantApp;
    
        /** verbose logging flag. this flag is set thru developer debugging options
         * and used so as to assist with in-the-field WiFi connectivity debugging  */
        public static int mVerboseLogging = 0;
    
        /* End of "used in Wifi Setup context" */
    
        /** A restricted multimap for use in constructAccessPoints */
        private static class Multimap<K,V> {
            private final HashMap<K,List<V>> store = new HashMap<K,List<V>>();
            /** retrieve a non-null list of values with key K */
            List<V> getAll(K key) {
                List<V> values = store.get(key);
                return values != null ? values : Collections.<V>emptyList();
            }
    
            void put(K key, V val) {
                List<V> curVals = store.get(key);
                if (curVals == null) {
                    curVals = new ArrayList<V>(3);
                    store.put(key, curVals);
                }
                curVals.add(val);
            }
        }
    
        private static class Scanner extends Handler {
            private int mRetry = 0;
            private WifiSettings mWifiSettings = null;
    
            Scanner(WifiSettings wifiSettings) {
                mWifiSettings = wifiSettings;
            }
    
            void resume() {
                if (!hasMessages(0)) {
                    sendEmptyMessage(0);
                }
            }
    
            void forceScan() {
                removeMessages(0);
                sendEmptyMessage(0);
            }
    
            void pause() {
                mRetry = 0;
                removeMessages(0);
            }
    
            @Override
            public void handleMessage(Message message) {
                if (mWifiSettings.mWifiManager.startScan()) {
                    mRetry = 0;
                } else if (++mRetry >= 3) {
                    mRetry = 0;
                    Activity activity = mWifiSettings.getActivity();
                    if (activity != null) {
                        Toast.makeText(activity, R.string.wifi_fail_to_scan, Toast.LENGTH_LONG).show();
                    }
                    return;
                }
                sendEmptyMessageDelayed(0, WIFI_RESCAN_INTERVAL_MS);
            }
        }
    
        public WifiSettings() {
            super(DISALLOW_CONFIG_WIFI);
            mFilter = new IntentFilter();
            mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
            mFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
            mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
            mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
            mFilter.addAction(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION);
            mFilter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
            mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
            mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
    
            mReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    handleEvent(intent);
                }
            };
    
            mScanner = new Scanner(this);
        }
    
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
    
            mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
    
            mConnectListener = new WifiManager.ActionListener() {
                                       @Override
                                       public void onSuccess() {
                                       }
                                       @Override
                                       public void onFailure(int reason) {
                                           Activity activity = getActivity();
                                           if (activity != null) {
                                               Toast.makeText(activity,
                                                    R.string.wifi_failed_connect_message,
                                                    Toast.LENGTH_SHORT).show();
                                           }
                                       }
                                   };
    
            mSaveListener = new WifiManager.ActionListener() {
                                    @Override
                                    public void onSuccess() {
                                    }
                                    @Override
                                    public void onFailure(int reason) {
                                        Activity activity = getActivity();
                                        if (activity != null) {
                                            Toast.makeText(activity,
                                                R.string.wifi_failed_save_message,
                                                Toast.LENGTH_SHORT).show();
                                        }
                                    }
                                };
    
            mForgetListener = new WifiManager.ActionListener() {
                                       @Override
                                       public void onSuccess() {
                                       }
                                       @Override
                                       public void onFailure(int reason) {
                                           Activity activity = getActivity();
                                           if (activity != null) {
                                               Toast.makeText(activity,
                                                   R.string.wifi_failed_forget_message,
                                                   Toast.LENGTH_SHORT).show();
                                           }
                                       }
                                   };
    
            if (savedInstanceState != null) {
                mDlgEdit = savedInstanceState.getBoolean(SAVE_DIALOG_EDIT_MODE);
                if (savedInstanceState.containsKey(SAVE_DIALOG_ACCESS_POINT_STATE)) {
                    mAccessPointSavedState =
                        savedInstanceState.getBundle(SAVE_DIALOG_ACCESS_POINT_STATE);
                }
            }
    
            // if we're supposed to enable/disable the Next button based on our current connection
            // state, start it off in the right state
            Intent intent = getActivity().getIntent();
            mEnableNextOnConnection = intent.getBooleanExtra(EXTRA_ENABLE_NEXT_ON_CONNECT, false);
    
            if (mEnableNextOnConnection) {
                if (hasNextButton()) {
                    final ConnectivityManager connectivity = (ConnectivityManager)
                            getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
                    if (connectivity != null) {
                        NetworkInfo info = connectivity.getNetworkInfo(
                                ConnectivityManager.TYPE_WIFI);
                        changeNextButtonState(info.isConnected());
                    }
                }
            }
    
            addPreferencesFromResource(R.xml.wifi_settings);
    
            prepareWifiAssistantCard();
    
            mEmptyView = initEmptyView();
            registerForContextMenu(getListView());
            setHasOptionsMenu(true);
        }
    
        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
            if (requestCode == REQUEST_ENABLE_WIFI_ASSISTANT) {
                if (resultCode == Activity.RESULT_OK) {
                    disableWifiAssistantCardUntilPlatformUpgrade();
                    getListView().removeHeaderView(mWifiAssistantCard);
                    mWifiAssistantApp = null;
                }
            } else {
                super.onActivityResult(requestCode, resultCode, resultData);
            }
        }
    
        @Override
        public void onDestroyView() {
            super.onDestroyView();
    
            if (mWifiEnabler != null) {
                mWifiEnabler.teardownSwitchBar();
            }
        }
    
        @Override
        public void onStart() {
            super.onStart();
    
            // On/off switch is hidden for Setup Wizard (returns null)
            mWifiEnabler = createWifiEnabler();
        }
    
        /**
         * @return new WifiEnabler or null (as overridden by WifiSettingsForSetupWizard)
         */
        /* package */ WifiEnabler createWifiEnabler() {
            final SettingsActivity activity = (SettingsActivity) getActivity();
            return new WifiEnabler(activity, activity.getSwitchBar());
        }
    
        @Override
        public void onResume() {
            final Activity activity = getActivity();
            super.onResume();
            if (mWifiEnabler != null) {
                mWifiEnabler.resume(activity);
            }
    
            activity.registerReceiver(mReceiver, mFilter);
            updateAccessPoints();
        }
    
        @Override
        public void onPause() {
            super.onPause();
            if (mWifiEnabler != null) {
                mWifiEnabler.pause();
            }
    
            getActivity().unregisterReceiver(mReceiver);
            mScanner.pause();
        }
    
        @Override
        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
            // If the user is not allowed to configure wifi, do not show the menu.
            if (isUiRestricted()) return;
    
            addOptionsMenuItems(menu);
            super.onCreateOptionsMenu(menu, inflater);
        }
    
        /**
         * @param menu
         */
        void addOptionsMenuItems(Menu menu) {
            final boolean wifiIsEnabled = mWifiManager.isWifiEnabled();
            TypedArray ta = getActivity().getTheme().obtainStyledAttributes(
                    new int[] {R.attr.ic_menu_add, R.attr.ic_wps});
            menu.add(Menu.NONE, MENU_ID_ADD_NETWORK, 0, R.string.wifi_add_network)
                    .setIcon(ta.getDrawable(0))
                    .setEnabled(wifiIsEnabled)
                    .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
            if (savedNetworksExist) {
                menu.add(Menu.NONE, MENU_ID_SAVED_NETWORK, 0, R.string.wifi_saved_access_points_label)
                        .setIcon(ta.getDrawable(0))
                        .setEnabled(wifiIsEnabled)
                        .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
            }
            menu.add(Menu.NONE, MENU_ID_SCAN, 0, R.string.menu_stats_refresh)
                   .setEnabled(wifiIsEnabled)
                   .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
            menu.add(Menu.NONE, MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced)
                    .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
            ta.recycle();
        }
    
        @Override
        public void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
    
            // If the dialog is showing, save its state.
            if (mDialog != null && mDialog.isShowing()) {
                outState.putBoolean(SAVE_DIALOG_EDIT_MODE, mDlgEdit);
                if (mDlgAccessPoint != null) {
                    mAccessPointSavedState = new Bundle();
                    mDlgAccessPoint.saveWifiState(mAccessPointSavedState);
                    outState.putBundle(SAVE_DIALOG_ACCESS_POINT_STATE, mAccessPointSavedState);
                }
            }
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // If the user is not allowed to configure wifi, do not handle menu selections.
            if (isUiRestricted()) return false;
    
            switch (item.getItemId()) {
                case MENU_ID_WPS_PBC:
                    showDialog(WPS_PBC_DIALOG_ID);
                    return true;
                    /*
                case MENU_ID_P2P:
                    if (getActivity() instanceof SettingsActivity) {
                        ((SettingsActivity) getActivity()).startPreferencePanel(
                                WifiP2pSettings.class.getCanonicalName(),
                                null,
                                R.string.wifi_p2p_settings_title, null,
                                this, 0);
                    } else {
                        startFragment(this, WifiP2pSettings.class.getCanonicalName(),
                                R.string.wifi_p2p_settings_title, -1, null);
                    }
                    return true;
                    */
                case MENU_ID_WPS_PIN:
                    showDialog(WPS_PIN_DIALOG_ID);
                    return true;
                case MENU_ID_SCAN:
                    if (mWifiManager.isWifiEnabled()) {
                        mScanner.forceScan();
                    }
                    return true;
                case MENU_ID_ADD_NETWORK:
                    if (mWifiManager.isWifiEnabled()) {
                        onAddNetworkPressed();
                    }
                    return true;
                case MENU_ID_SAVED_NETWORK:
                    if (getActivity() instanceof SettingsActivity) {
                        ((SettingsActivity) getActivity()).startPreferencePanel(
                                SavedAccessPointsWifiSettings.class.getCanonicalName(), null,
                                R.string.wifi_saved_access_points_titlebar, null, this, 0);
                    } else {
                        startFragment(this, SavedAccessPointsWifiSettings.class.getCanonicalName(),
                                R.string.wifi_saved_access_points_titlebar,
                                -1 /* Do not request a result */, null);
                    }
                    return true;
                case MENU_ID_ADVANCED:
                    if (getActivity() instanceof SettingsActivity) {
                        ((SettingsActivity) getActivity()).startPreferencePanel(
                                AdvancedWifiSettings.class.getCanonicalName(), null,
                                R.string.wifi_advanced_titlebar, null, this, 0);
                    } else {
                        startFragment(this, AdvancedWifiSettings.class.getCanonicalName(),
                                R.string.wifi_advanced_titlebar, -1 /* Do not request a results */,
                                null);
                    }
                    return true;
            }
            return super.onOptionsItemSelected(item);
        }
    
        @Override
        public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) {
            if (info instanceof AdapterContextMenuInfo) {
                Preference preference = (Preference) getListView().getItemAtPosition(
                        ((AdapterContextMenuInfo) info).position);
    
                if (preference instanceof AccessPoint) {
                    mSelectedAccessPoint = (AccessPoint) preference;
                    menu.setHeaderTitle(mSelectedAccessPoint.ssid);
                    if (mSelectedAccessPoint.getLevel() != -1
                            && mSelectedAccessPoint.getState() == null) {
                        menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect);
                    }
                    if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
                        if (ActivityManager.getCurrentUser() == UserHandle.USER_OWNER) {
                            menu.add(Menu.NONE, MENU_ID_FORGET, 0, R.string.wifi_menu_forget);
                        }
                        menu.add(Menu.NONE, MENU_ID_MODIFY, 0, R.string.wifi_menu_modify);
    
                        if (mSelectedAccessPoint.security != AccessPoint.SECURITY_NONE) {
                            // Only allow writing of NFC tags for password-protected networks.
                            menu.add(Menu.NONE, MENU_ID_WRITE_NFC, 0, R.string.wifi_menu_write_to_nfc);
                        }
                    }
                }
            }
        }
    
        @Override
        public boolean onContextItemSelected(MenuItem item) {
            if (mSelectedAccessPoint == null) {
                return super.onContextItemSelected(item);
            }
            switch (item.getItemId()) {
                case MENU_ID_CONNECT: {
                    if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
                        connect(mSelectedAccessPoint.networkId);
                    } else if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE) {
                        /** Bypass dialog for unsecured networks */
                        mSelectedAccessPoint.generateOpenNetworkConfig();
                        connect(mSelectedAccessPoint.getConfig());
                    } else {
                        showDialog(mSelectedAccessPoint, true);
                    }
                    return true;
                }
                case MENU_ID_FORGET: {
                    mWifiManager.forget(mSelectedAccessPoint.networkId, mForgetListener);
                    return true;
                }
                case MENU_ID_MODIFY: {
                    showDialog(mSelectedAccessPoint, true);
                    return true;
                }
                case MENU_ID_WRITE_NFC:
                    showDialog(WRITE_NFC_DIALOG_ID);
                    return true;
    
            }
            return super.onContextItemSelected(item);
        }
    
        @Override
        public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
            if (preference instanceof AccessPoint) {
                mSelectedAccessPoint = (AccessPoint) preference;
                /** Bypass dialog for unsecured, unsaved networks */
                if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE &&
                        mSelectedAccessPoint.networkId == INVALID_NETWORK_ID) {
                    mSelectedAccessPoint.generateOpenNetworkConfig();
                    if (!savedNetworksExist) {
                        savedNetworksExist = true;
                        getActivity().invalidateOptionsMenu();
                    }
                    connect(mSelectedAccessPoint.getConfig());
                } else {
                    showDialog(mSelectedAccessPoint, false);
                }
            } else {
                return super.onPreferenceTreeClick(screen, preference);
            }
            return true;
        }
    
        private void showDialog(AccessPoint accessPoint, boolean edit) {
            if (mDialog != null) {
                removeDialog(WIFI_DIALOG_ID);
                mDialog = null;
            }
    
            // Save the access point and edit mode
            mDlgAccessPoint = accessPoint;
            mDlgEdit = edit;
    
            showDialog(WIFI_DIALOG_ID);
        }
    
        @Override
        public Dialog onCreateDialog(int dialogId) {
            switch (dialogId) {
                case WIFI_DIALOG_ID:
                    AccessPoint ap = mDlgAccessPoint; // For manual launch
                    if (ap == null) { // For re-launch from saved state
                        if (mAccessPointSavedState != null) {
                            ap = new AccessPoint(getActivity(), mAccessPointSavedState);
                            // For repeated orientation changes
                            mDlgAccessPoint = ap;
                            // Reset the saved access point data
                            mAccessPointSavedState = null;
                        }
                    }
                    // If it's null, fine, it's for Add Network
                    mSelectedAccessPoint = ap;
                    mDialog = new WifiDialog(getActivity(), this, ap, mDlgEdit);
                    return mDialog;
                case WPS_PBC_DIALOG_ID:
                    return new WpsDialog(getActivity(), WpsInfo.PBC);
                case WPS_PIN_DIALOG_ID:
                    return new WpsDialog(getActivity(), WpsInfo.DISPLAY);
                case WRITE_NFC_DIALOG_ID:
                    if (mSelectedAccessPoint != null) {
                        mWifiToNfcDialog = new WriteWifiConfigToNfcDialog(
                                getActivity(), mSelectedAccessPoint, mWifiManager);
                        return mWifiToNfcDialog;
                    }
    
            }
            return super.onCreateDialog(dialogId);
        }
    
        /**
         * Shows the latest access points available with supplemental information like
         * the strength of network and the security for it.
         */
        private void updateAccessPoints() {
            // Safeguard from some delayed event handling
            if (getActivity() == null) return;
    
            if (isUiRestricted()) {
                addMessagePreference(R.string.wifi_empty_list_user_restricted);
                return;
            }
            final int wifiState = mWifiManager.getWifiState();
    
            //when we update the screen, check if verbose logging has been turned on or off
            mVerboseLogging = mWifiManager.getVerboseLoggingLevel();
    
            switch (wifiState) {
                case WifiManager.WIFI_STATE_ENABLED:
                    // AccessPoints are automatically sorted with TreeSet.
                    final Collection<AccessPoint> accessPoints =
                            constructAccessPoints(getActivity(), mWifiManager, mLastInfo, mLastState);
                    getPreferenceScreen().removeAll();
                    if (accessPoints.size() == 0) {
                        addMessagePreference(R.string.wifi_empty_list_wifi_on);
                    }
    
                    getListView().removeHeaderView(mWifiAssistantCard);
                    if (mWifiAssistantApp != null) {
                        getListView().addHeaderView(mWifiAssistantCard);
                    }
    
                    for (AccessPoint accessPoint : accessPoints) {
                        // Ignore access points that are out of range.
                        if (accessPoint.getLevel() != -1) {
                            getPreferenceScreen().addPreference(accessPoint);
                        }
                    }
                    break;
    
                case WifiManager.WIFI_STATE_ENABLING:
                    getPreferenceScreen().removeAll();
                    break;
    
                case WifiManager.WIFI_STATE_DISABLING:
                    addMessagePreference(R.string.wifi_stopping);
                    break;
    
                case WifiManager.WIFI_STATE_DISABLED:
                    setOffMessage();
                    break;
            }
        }
    
        /**
         * Returns the Network Scorer for the Wifi Assistant App.
         */
        public static NetworkScorerAppData getWifiAssistantApp(Context context) {
            Collection<NetworkScorerAppData> scorers =
                    NetworkScorerAppManager.getAllValidScorers(context);
    
            if (scorers.isEmpty()) {
                return null;
            }
    
            // TODO: b/13780935 - Implement proper scorer selection. Rather than pick the first
            // scorer on the system, we should allow the user to select one.
            return scorers.iterator().next();
        }
    
        private void prepareWifiAssistantCard() {
            if (getActivity() instanceof WifiPickerActivity) {
                return;
            }
    
            if (NetworkScorerAppManager.getActiveScorer(getActivity()) != null) {
                // A scorer is already enabled; don't show the card.
                return;
            }
    
            Collection<NetworkScorerAppData> scorers =
                    NetworkScorerAppManager.getAllValidScorers(getActivity());
            if (scorers.isEmpty()) {
                // No scorers are available to enable; don't show the card.
                return;
            }
    
            SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
            int lastDismissPlatform = sharedPreferences.getInt(KEY_ASSISTANT_DISMISS_PLATFORM, 0);
    
            if (Build.VERSION.SDK_INT <= lastDismissPlatform) {
                // User has dismissed the Wi-Fi assistant card on this SDK release. Suppress the card
                // until the next major platform upgrade.
                return;
            }
    
            // TODO: b/13780935 - Implement proper scorer selection. Rather than pick the first
            // scorer on the system, we should allow the user to select one.
            mWifiAssistantApp = scorers.iterator().next();
    
            if (mWifiAssistantCard == null) {
                mWifiAssistantCard = LayoutInflater.from(getActivity())
                        .inflate(R.layout.wifi_assistant_card, getListView(), false);
                Button setup = (Button) mWifiAssistantCard.findViewById(R.id.setup);
                Button noThanks = (Button) mWifiAssistantCard.findViewById(R.id.no_thanks_button);
                TextView assistantText =
                    (TextView) mWifiAssistantCard.findViewById(R.id.wifi_assistant_text);
                assistantText.setText(getResources().getString(
                        R.string.wifi_assistant_title_message, mWifiAssistantApp.mScorerName));
    
                if (setup != null && noThanks != null) {
                    setup.setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            Intent intent = new Intent();
                            if (mWifiAssistantApp.mConfigurationActivityClassName != null) {
                                // App has a custom configuration activity; launch that.
                                // This custom activity will be responsible for launching the system
                                // dialog.
                                intent.setClassName(mWifiAssistantApp.mPackageName,
                                        mWifiAssistantApp.mConfigurationActivityClassName);
                            } else {
                                // Fall back on the system dialog.
                                intent.setAction(NetworkScoreManager.ACTION_CHANGE_ACTIVE);
                                intent.putExtra(NetworkScoreManager.EXTRA_PACKAGE_NAME,
                                        mWifiAssistantApp.mPackageName);
                            }
                            startActivityForResult(intent, REQUEST_ENABLE_WIFI_ASSISTANT);
                        }
                    });
    
                    noThanks.setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            disableWifiAssistantCardUntilPlatformUpgrade();
                            getListView().removeHeaderView(mWifiAssistantCard);
                            mWifiAssistantApp = null;
                        }
                    });
                }
            }
        }
    
        private void disableWifiAssistantCardUntilPlatformUpgrade() {
            SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
            SharedPreferences.Editor editor = sharedPreferences.edit();
            editor.putInt(KEY_ASSISTANT_DISMISS_PLATFORM, Build.VERSION.SDK_INT);
            editor.apply();
        }
    
        protected TextView initEmptyView() {
            TextView emptyView = (TextView) getActivity().findViewById(android.R.id.empty);
            getListView().setEmptyView(emptyView);
            return emptyView;
        }
    
        private void setOffMessage() {
            if (mEmptyView != null) {
                mEmptyView.setText(R.string.wifi_empty_list_wifi_off);
                if (android.provider.Settings.Global.getInt(getActivity().getContentResolver(),
                        android.provider.Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1) {
                    mEmptyView.append("\n\n");
                    int resId;
                    if (android.provider.Settings.Secure.isLocationProviderEnabled(
                            getActivity().getContentResolver(), LocationManager.NETWORK_PROVIDER)) {
                        resId = R.string.wifi_scan_notify_text_location_on;
                    } else {
                        resId = R.string.wifi_scan_notify_text_location_off;
                    }
                    CharSequence charSeq = getText(resId);
                    mEmptyView.append(charSeq);
                }
            }
            getPreferenceScreen().removeAll();
        }
    
        private void addMessagePreference(int messageId) {
            if (mEmptyView != null) mEmptyView.setText(messageId);
            getPreferenceScreen().removeAll();
        }
    
        /** Returns sorted list of access points */
        private static List<AccessPoint> constructAccessPoints(Context context,
                WifiManager wifiManager, WifiInfo lastInfo, DetailedState lastState) {
            ArrayList<AccessPoint> accessPoints = new ArrayList<AccessPoint>();
            /** Lookup table to more quickly update AccessPoints by only considering objects with the
             * correct SSID.  Maps SSID -> List of AccessPoints with the given SSID.  */
            Multimap<String, AccessPoint> apMap = new Multimap<String, AccessPoint>();
    
            final List<WifiConfiguration> configs = wifiManager.getConfiguredNetworks();
            if (configs != null) {
                // Update "Saved Networks" menu option.
                if (savedNetworksExist != (configs.size() > 0)) {
                    savedNetworksExist = !savedNetworksExist;
                    if (context instanceof Activity) {
                        ((Activity) context).invalidateOptionsMenu();
                    }
                }
                for (WifiConfiguration config : configs) {
                    if (config.selfAdded && config.numAssociation == 0) {
                        continue;
                    }
                    AccessPoint accessPoint = new AccessPoint(context, config);
                    if (lastInfo != null && lastState != null) {
                        accessPoint.update(lastInfo, lastState);
                    }
                    accessPoints.add(accessPoint);
                    apMap.put(accessPoint.ssid, accessPoint);
                }
            }
    
            final List<ScanResult> results = wifiManager.getScanResults();
            if (results != null) {
                for (ScanResult result : results) {
                    // Ignore hidden and ad-hoc networks.
                    if (result.SSID == null || result.SSID.length() == 0 ||
                            result.capabilities.contains("[IBSS]")) {
                        continue;
                    }
    
                    boolean found = false;
                    for (AccessPoint accessPoint : apMap.getAll(result.SSID)) {
                        if (accessPoint.update(result))
                            found = true;
                    }
                    if (!found) {
                        AccessPoint accessPoint = new AccessPoint(context, result);
                        accessPoints.add(accessPoint);
                        apMap.put(accessPoint.ssid, accessPoint);
                    }
                }
            }
    
            // Pre-sort accessPoints to speed preference insertion
            Collections.sort(accessPoints);
            return accessPoints;
        }
    
        private void handleEvent(Intent intent) {
            String action = intent.getAction();
            if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
                updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
                        WifiManager.WIFI_STATE_UNKNOWN));
            } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action) ||
                    WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action) ||
                    WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) {
                    updateAccessPoints();
            } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
                NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
                        WifiManager.EXTRA_NETWORK_INFO);
                mConnected.set(info.isConnected());
                changeNextButtonState(info.isConnected());
                updateAccessPoints();
                updateConnectionState(info.getDetailedState());
            } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
                updateConnectionState(null);
            }
        }
    
        private void updateConnectionState(DetailedState state) {
            /* sticky broadcasts can call this when wifi is disabled */
            if (!mWifiManager.isWifiEnabled()) {
                mScanner.pause();
                return;
            }
    
            if (state == DetailedState.OBTAINING_IPADDR) {
                mScanner.pause();
            } else {
                mScanner.resume();
            }
    
            mLastInfo = mWifiManager.getConnectionInfo();
            if (state != null) {
                mLastState = state;
            }
    
            for (int i = getPreferenceScreen().getPreferenceCount() - 1; i >= 0; --i) {
                // Maybe there's a WifiConfigPreference
                Preference preference = getPreferenceScreen().getPreference(i);
                if (preference instanceof AccessPoint) {
                    final AccessPoint accessPoint = (AccessPoint) preference;
                    accessPoint.update(mLastInfo, mLastState);
                }
            }
        }
    
        private void updateWifiState(int state) {
            Activity activity = getActivity();
            if (activity != null) {
                activity.invalidateOptionsMenu();
            }
    
            switch (state) {
                case WifiManager.WIFI_STATE_ENABLED:
                    mScanner.resume();
                    return; // not break, to avoid the call to pause() below
    
                case WifiManager.WIFI_STATE_ENABLING:
                    addMessagePreference(R.string.wifi_starting);
                    break;
    
                case WifiManager.WIFI_STATE_DISABLED:
                    setOffMessage();
                    break;
            }
    
            mLastInfo = null;
            mLastState = null;
            mScanner.pause();
        }
    
        /**
         * Renames/replaces "Next" button when appropriate. "Next" button usually exists in
         * Wifi setup screens, not in usual wifi settings screen.
         *
         * @param enabled true when the device is connected to a wifi network.
         */
        private void changeNextButtonState(boolean enabled) {
            if (mEnableNextOnConnection && hasNextButton()) {
                getNextButton().setEnabled(enabled);
            }
        }
    
        @Override
        public void onClick(DialogInterface dialogInterface, int button) {
            if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) {
                forget();
            } else if (button == WifiDialog.BUTTON_SUBMIT) {
                if (mDialog != null) {
                    submit(mDialog.getController());
                }
            }
        }
    
        /* package */ void submit(WifiConfigController configController) {
    
            final WifiConfiguration config = configController.getConfig();
    
            if (config == null) {
                if (mSelectedAccessPoint != null
                        && mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
                    connect(mSelectedAccessPoint.networkId);
                }
            } else if (config.networkId != INVALID_NETWORK_ID) {
                if (mSelectedAccessPoint != null) {
                    mWifiManager.save(config, mSaveListener);
                }
            } else {
                if (configController.isEdit()) {
                    mWifiManager.save(config, mSaveListener);
                } else {
                    connect(config);
                }
            }
    
            if (mWifiManager.isWifiEnabled()) {
                mScanner.resume();
            }
            updateAccessPoints();
        }
    
        /* package */ void forget() {
            if (mSelectedAccessPoint.networkId == INVALID_NETWORK_ID) {
                // Should not happen, but a monkey seems to trigger it
                Log.e(TAG, "Failed to forget invalid network " + mSelectedAccessPoint.getConfig());
                return;
            }
    
            mWifiManager.forget(mSelectedAccessPoint.networkId, mForgetListener);
    
            if (mWifiManager.isWifiEnabled()) {
                mScanner.resume();
            }
            updateAccessPoints();
    
            // We need to rename/replace "Next" button in wifi setup context.
            changeNextButtonState(false);
        }
    
        protected void connect(final WifiConfiguration config) {
            mWifiManager.connect(config, mConnectListener);
        }
    
        protected void connect(final int networkId) {
            mWifiManager.connect(networkId, mConnectListener);
        }
    
        /**
         * Refreshes acccess points and ask Wifi module to scan networks again.
         */
        /* package */ void refreshAccessPoints() {
            if (mWifiManager.isWifiEnabled()) {
                mScanner.resume();
            }
    
            getPreferenceScreen().removeAll();
        }
    
        /**
         * Called when "add network" button is pressed.
         */
        /* package */ void onAddNetworkPressed() {
            // No exact access point is selected.
            mSelectedAccessPoint = null;
            showDialog(null, true);
        }
    
        /* package */ int getAccessPointsCount() {
            final boolean wifiIsEnabled = mWifiManager.isWifiEnabled();
            if (wifiIsEnabled) {
                return getPreferenceScreen().getPreferenceCount();
            } else {
                return 0;
            }
        }
    
        /**
         * Requests wifi module to pause wifi scan. May be ignored when the module is disabled.
         */
        /* package */ void pauseWifiScan() {
            if (mWifiManager.isWifiEnabled()) {
                mScanner.pause();
            }
        }
    
        /**
         * Requests wifi module to resume wifi scan. May be ignored when the module is disabled.
         */
        /* package */ void resumeWifiScan() {
            if (mWifiManager.isWifiEnabled()) {
                mScanner.resume();
            }
        }
    
        @Override
        protected int getHelpResource() {
            return R.string.help_url_wifi;
        }
    
        public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
            new BaseSearchIndexProvider() {
                @Override
                public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
                    final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
                    final Resources res = context.getResources();
    
                    // Add fragment title
                    SearchIndexableRaw data = new SearchIndexableRaw(context);
                    data.title = res.getString(R.string.wifi_settings);
                    data.screenTitle = res.getString(R.string.wifi_settings);
                    data.keywords = res.getString(R.string.keywords_wifi);
                    result.add(data);
    
                    // Add available Wi-Fi access points
                    WifiManager wifiManager =
                            (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
                    final Collection<AccessPoint> accessPoints =
                            constructAccessPoints(context, wifiManager, null, null);
                    for (AccessPoint accessPoint : accessPoints) {
                        // We are indexing only the saved Wi-Fi networks.
                        if (accessPoint.getConfig() == null) continue;
                        data = new SearchIndexableRaw(context);
                        data.title = accessPoint.getTitle().toString();
                        data.screenTitle = res.getString(R.string.wifi_settings);
                        data.enabled = enabled;
                        result.add(data);
                    }
    
                    return result;
                }
            };
    }
    
    
    /*
     * Copyright (C) 2010 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package com.android.settings.wifi;
    
    import com.android.settings.R;
    
    import android.content.Context;
    import android.graphics.drawable.Drawable;
    import android.graphics.drawable.StateListDrawable;
    import android.net.NetworkInfo.DetailedState;
    import android.net.wifi.ScanResult;
    import android.net.wifi.WifiConfiguration;
    import android.net.wifi.WifiConfiguration.KeyMgmt;
    import android.net.wifi.WifiInfo;
    import android.net.wifi.WifiManager;
    import android.os.Bundle;
    import android.preference.Preference;
    import android.util.Log;
    import android.util.LruCache;
    import android.view.View;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    import java.util.Map;
    
    
    class AccessPoint extends Preference {
        static final String TAG = "Settings.AccessPoint";
    
        /**
         * Lower bound on the 2.4 GHz (802.11b/g/n) WLAN channels
         */
        public static final int LOWER_FREQ_24GHZ = 2400;
    
        /**
         * Upper bound on the 2.4 GHz (802.11b/g/n) WLAN channels
         */
        public static final int HIGHER_FREQ_24GHZ = 2500;
    
        /**
         * Lower bound on the 5.0 GHz (802.11a/h/j/n/ac) WLAN channels
         */
        public static final int LOWER_FREQ_5GHZ = 4900;
    
        /**
         * Upper bound on the 5.0 GHz (802.11a/h/j/n/ac) WLAN channels
         */
        public static final int HIGHER_FREQ_5GHZ = 5900;
    
        /**
         * Experimental: we should be able to show the user the list of BSSIDs and bands
         *  for that SSID.
         *  For now this data is used only with Verbose Logging so as to show the band and number
         *  of BSSIDs on which that network is seen.
         */
        public LruCache<String, ScanResult> mScanResultCache;
    
    
        private static final String KEY_DETAILEDSTATE = "key_detailedstate";
        private static final String KEY_WIFIINFO = "key_wifiinfo";
        private static final String KEY_SCANRESULT = "key_scanresult";
        private static final String KEY_CONFIG = "key_config";
    
        private static final int[] STATE_SECURED = {
            R.attr.state_encrypted
        };
        private static final int[] STATE_NONE = {};
    
        private static int[] wifi_signal_attributes = { R.attr.wifi_signal };
    
        /**
         * These values are matched in string arrays -- changes must be kept in sync
         */
        static final int SECURITY_NONE = 0;
        static final int SECURITY_WEP = 1;
        static final int SECURITY_PSK = 2;
        static final int SECURITY_EAP = 3;
    
        enum PskType {
            UNKNOWN,
            WPA,
            WPA2,
            WPA_WPA2
        }
    
        String ssid;
        String bssid;
        int security;
        int networkId = -1;
        boolean wpsAvailable = false;
        boolean showSummary = true;
    
        PskType pskType = PskType.UNKNOWN;
    
        private WifiConfiguration mConfig;
        /* package */ScanResult mScanResult;
    
        private int mRssi = Integer.MAX_VALUE;
        private long mSeen = 0;
    
        private WifiInfo mInfo;
        private DetailedState mState;
    
        private static final int VISIBILITY_MAX_AGE_IN_MILLI = 1000000;
        private static final int VISIBILITY_OUTDATED_AGE_IN_MILLI = 20000;
        private static final int SECOND_TO_MILLI = 1000;
    
        static int getSecurity(WifiConfiguration config) {
            if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
                return SECURITY_PSK;
            }
            if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
                    config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
                return SECURITY_EAP;
            }
            return (config.wepKeys[0] != null) ? SECURITY_WEP : SECURITY_NONE;
        }
    
        private static int getSecurity(ScanResult result) {
            if (result.capabilities.contains("WEP")) {
                return SECURITY_WEP;
            } else if (result.capabilities.contains("PSK")) {
                return SECURITY_PSK;
            } else if (result.capabilities.contains("EAP")) {
                return SECURITY_EAP;
            }
            return SECURITY_NONE;
        }
    
        public String getSecurityString(boolean concise) {
            Context context = getContext();
            switch(security) {
                case SECURITY_EAP:
                    return concise ? context.getString(R.string.wifi_security_short_eap) :
                        context.getString(R.string.wifi_security_eap);
                case SECURITY_PSK:
                    switch (pskType) {
                        case WPA:
                            return concise ? context.getString(R.string.wifi_security_short_wpa) :
                                context.getString(R.string.wifi_security_wpa);
                        case WPA2:
                            return concise ? context.getString(R.string.wifi_security_short_wpa2) :
                                context.getString(R.string.wifi_security_wpa2);
                        case WPA_WPA2:
                            return concise ? context.getString(R.string.wifi_security_short_wpa_wpa2) :
                                context.getString(R.string.wifi_security_wpa_wpa2);
                        case UNKNOWN:
                        default:
                            return concise ? context.getString(R.string.wifi_security_short_psk_generic)
                                    : context.getString(R.string.wifi_security_psk_generic);
                    }
                case SECURITY_WEP:
                    return concise ? context.getString(R.string.wifi_security_short_wep) :
                        context.getString(R.string.wifi_security_wep);
                case SECURITY_NONE:
                default:
                    return concise ? "" : context.getString(R.string.wifi_security_none);
            }
        }
    
        private static PskType getPskType(ScanResult result) {
            boolean wpa = result.capabilities.contains("WPA-PSK");
            boolean wpa2 = result.capabilities.contains("WPA2-PSK");
            if (wpa2 && wpa) {
                return PskType.WPA_WPA2;
            } else if (wpa2) {
                return PskType.WPA2;
            } else if (wpa) {
                return PskType.WPA;
            } else {
                Log.w(TAG, "Received abnormal flag string: " + result.capabilities);
                return PskType.UNKNOWN;
            }
        }
    
        AccessPoint(Context context, WifiConfiguration config) {
            super(context);
            loadConfig(config);
            refresh();
        }
    
        AccessPoint(Context context, ScanResult result) {
            super(context);
            loadResult(result);
            refresh();
        }
    
        AccessPoint(Context context, Bundle savedState) {
            super(context);
    
            mConfig = savedState.getParcelable(KEY_CONFIG);
            if (mConfig != null) {
                loadConfig(mConfig);
            }
            mScanResult = (ScanResult) savedState.getParcelable(KEY_SCANRESULT);
            if (mScanResult != null) {
                loadResult(mScanResult);
            }
            mInfo = (WifiInfo) savedState.getParcelable(KEY_WIFIINFO);
            if (savedState.containsKey(KEY_DETAILEDSTATE)) {
                mState = DetailedState.valueOf(savedState.getString(KEY_DETAILEDSTATE));
            }
            update(mInfo, mState);
        }
    
        public void saveWifiState(Bundle savedState) {
            savedState.putParcelable(KEY_CONFIG, mConfig);
            savedState.putParcelable(KEY_SCANRESULT, mScanResult);
            savedState.putParcelable(KEY_WIFIINFO, mInfo);
            if (mState != null) {
                savedState.putString(KEY_DETAILEDSTATE, mState.toString());
            }
        }
    
        private void loadConfig(WifiConfiguration config) {
            ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));
            bssid = config.BSSID;
            security = getSecurity(config);
            networkId = config.networkId;
            mConfig = config;
        }
    
        private void loadResult(ScanResult result) {
            ssid = result.SSID;
            bssid = result.BSSID;
            security = getSecurity(result);
            wpsAvailable = security != SECURITY_EAP && result.capabilities.contains("WPS");
            if (security == SECURITY_PSK)
                pskType = getPskType(result);
            mRssi = result.level;
            mScanResult = result;
            if (result.seen > mSeen) {
                mSeen = result.seen;
            }
        }
    
        @Override
        protected void onBindView(View view) {
            super.onBindView(view);
            updateIcon(getLevel(), getContext());
    
            final TextView summaryView = (TextView) view.findViewById(
                    com.android.internal.R.id.summary);
            summaryView.setVisibility(showSummary ? View.VISIBLE : View.GONE);
    
            notifyChanged();
        }
    
        protected void updateIcon(int level, Context context) {
            if (level == -1) {
                setIcon(null);
            } else {
                Drawable drawable = getIcon();
    
                if (drawable == null) {
                    // To avoid a drawing race condition, we first set the state (SECURE/NONE) and then
                    // set the icon (drawable) to that state's drawable.
                    StateListDrawable sld = (StateListDrawable) context.getTheme()
                            .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0);
                    // If sld is null then we are indexing and therefore do not have access to
                    // (nor need to display) the drawable.
                    if (sld != null) {
                        sld.setState((security != SECURITY_NONE) ? STATE_SECURED : STATE_NONE);
                        drawable = sld.getCurrent();
                        setIcon(drawable);
                    }
                }
    
                if (drawable != null) {
                    drawable.setLevel(level);
                }
            }
        }
    
        @Override
        public int compareTo(Preference preference) {
            if (!(preference instanceof AccessPoint)) {
                return 1;
            }
            AccessPoint other = (AccessPoint) preference;
            // Active one goes first.
            if (mInfo != null && other.mInfo == null) return -1;
            if (mInfo == null && other.mInfo != null) return 1;
    
            // Reachable one goes before unreachable one.
            if (mRssi != Integer.MAX_VALUE && other.mRssi == Integer.MAX_VALUE) return -1;
            if (mRssi == Integer.MAX_VALUE && other.mRssi != Integer.MAX_VALUE) return 1;
            if (mRssi == Integer.MAX_VALUE && other.mRssi != Integer.MAX_VALUE) return 1;
    
            // Configured one goes before unconfigured one.
            if (networkId != WifiConfiguration.INVALID_NETWORK_ID
                    && other.networkId == WifiConfiguration.INVALID_NETWORK_ID) return -1;
            if (networkId == WifiConfiguration.INVALID_NETWORK_ID
                    && other.networkId != WifiConfiguration.INVALID_NETWORK_ID) return 1;
    
            // Sort by signal strength.
            int difference = WifiManager.compareSignalLevel(other.mRssi, mRssi);
            if (difference != 0) {
                return difference;
            }
            // Sort by ssid.
            return ssid.compareToIgnoreCase(other.ssid);
        }
    
        @Override
        public boolean equals(Object other) {
            if (!(other instanceof AccessPoint)) return false;
            return (this.compareTo((AccessPoint) other) == 0);
        }
    
        @Override
        public int hashCode() {
            int result = 0;
            if (mInfo != null) result += 13 * mInfo.hashCode();
            result += 19 * mRssi;
            result += 23 * networkId;
            result += 29 * ssid.hashCode();
            return result;
        }
    
        boolean update(ScanResult result) {
            if (result.seen > mSeen) {
                mSeen = result.seen;
            }
            if (WifiSettings.mVerboseLogging > 0) {
                if (mScanResultCache == null) {
                    mScanResultCache = new LruCache<String, ScanResult>(32);
                }
                mScanResultCache.put(result.BSSID, result);
            }
    
            if (ssid.equals(result.SSID) && security == getSecurity(result)) {
                if (WifiManager.compareSignalLevel(result.level, mRssi) > 0) {
                    int oldLevel = getLevel();
                    mRssi = result.level;
                    if (getLevel() != oldLevel) {
                        notifyChanged();
                    }
                }
                // This flag only comes from scans, is not easily saved in config
                if (security == SECURITY_PSK) {
                    pskType = getPskType(result);
                }
                mScanResult = result;
                refresh();
                return true;
            }
            return false;
        }
    
        void update(WifiInfo info, DetailedState state) {
            boolean reorder = false;
            if (info != null && networkId != WifiConfiguration.INVALID_NETWORK_ID
                    && networkId == info.getNetworkId()) {
                reorder = (mInfo == null);
                mRssi = info.getRssi();
                mInfo = info;
                mState = state;
                refresh();
            } else if (mInfo != null) {
                reorder = true;
                mInfo = null;
                mState = null;
                refresh();
            }
            if (reorder) {
                notifyHierarchyChanged();
            }
        }
    
        int getLevel() {
            if (mRssi == Integer.MAX_VALUE) {
                return -1;
            }
            return WifiManager.calculateSignalLevel(mRssi, 4);
        }
    
        WifiConfiguration getConfig() {
            return mConfig;
        }
    
        WifiInfo getInfo() {
            return mInfo;
        }
    
        DetailedState getState() {
            return mState;
        }
    
        static String removeDoubleQuotes(String string) {
            int length = string.length();
            if ((length > 1) && (string.charAt(0) == '"')
                    && (string.charAt(length - 1) == '"')) {
                return string.substring(1, length - 1);
            }
            return string;
        }
    
        static String convertToQuotedString(String string) {
            return "\"" + string + "\"";
        }
    
        /**
         * Shows or Hides the Summary of an AccessPoint.
         *
         * @param showSummary true will show the summary, false will hide the summary
         */
        public void setShowSummary(boolean showSummary){
            this.showSummary = showSummary;
        }
    
        /**
         * Returns the visibility status of the WifiConfiguration.
         *
         * @return autojoin debugging information
         * TODO: use a string formatter
         * ["rssi 5Ghz", "num results on 5GHz" / "rssi 5Ghz", "num results on 5GHz"]
         * For instance [-40,5/-30,2]
         */
        private String getVisibilityStatus() {
            StringBuilder visibility = new StringBuilder();
            StringBuilder scans24GHz = null;
            StringBuilder scans5GHz = null;
            String bssid = null;
    
            long now = System.currentTimeMillis();
    
            if (mInfo != null) {
                bssid = mInfo.getBSSID();
                if (bssid != null) {
                    visibility.append(" ").append(bssid);
                }
                visibility.append(" score=").append(mInfo.score);
                visibility.append(" ");
                visibility.append(String.format("tx=%.1f,", mInfo.txSuccessRate));
                visibility.append(String.format("%.1f,", mInfo.txRetriesRate));
                visibility.append(String.format("%.1f ", mInfo.txBadRate));
                visibility.append(String.format("rx=%.1f", mInfo.rxSuccessRate));
            }
    
            if (mScanResultCache != null) {
                int rssi5 = WifiConfiguration.INVALID_RSSI;
                int rssi24 = WifiConfiguration.INVALID_RSSI;
                int num5 = 0;
                int num24 = 0;
                int numBlackListed = 0;
                int n24 = 0; // Number scan results we included in the string
                int n5 = 0; // Number scan results we included in the string
                Map<String, ScanResult> list = mScanResultCache.snapshot();
                // TODO: sort list by RSSI or age
                for (ScanResult result : list.values()) {
                    if (result.seen == 0)
                        continue;
    
                    if (result.autoJoinStatus != ScanResult.ENABLED) numBlackListed++;
    
                    if (result.frequency >= LOWER_FREQ_5GHZ
                            && result.frequency <= HIGHER_FREQ_5GHZ) {
                        // Strictly speaking: [4915, 5825]
                        // number of known BSSID on 5GHz band
                        num5 = num5 + 1;
                    } else if (result.frequency >= LOWER_FREQ_24GHZ
                            && result.frequency <= HIGHER_FREQ_24GHZ) {
                        // Strictly speaking: [2412, 2482]
                        // number of known BSSID on 2.4Ghz band
                        num24 = num24 + 1;
                    }
    
                    // Ignore results seen, older than 20 seconds
                    if (now - result.seen > VISIBILITY_OUTDATED_AGE_IN_MILLI) continue;
    
                    if (result.frequency >= LOWER_FREQ_5GHZ
                            && result.frequency <= HIGHER_FREQ_5GHZ) {
                        if (result.level > rssi5) {
                            rssi5 = result.level;
                        }
                        if (n5 < 4) {
                            if (scans5GHz == null) scans5GHz = new StringBuilder();
                            scans5GHz.append(" {").append(result.BSSID);
                            if (bssid != null && result.BSSID.equals(bssid)) scans5GHz.append("*");
                            scans5GHz.append("=").append(result.frequency);
                            scans5GHz.append(",").append(result.level);
                            if (result.autoJoinStatus != 0) {
                                scans5GHz.append(",st=").append(result.autoJoinStatus);
                            }
                            if (result.numIpConfigFailures != 0) {
                                scans5GHz.append(",ipf=").append(result.numIpConfigFailures);
                            }
                            scans5GHz.append("}");
                            n5++;
                        }
                    } else if (result.frequency >= LOWER_FREQ_24GHZ
                            && result.frequency <= HIGHER_FREQ_24GHZ) {
                        if (result.level > rssi24) {
                            rssi24 = result.level;
                        }
                        if (n24 < 4) {
                            if (scans24GHz == null) scans24GHz = new StringBuilder();
                            scans24GHz.append(" {").append(result.BSSID);
                            if (bssid != null && result.BSSID.equals(bssid)) scans24GHz.append("*");
                            scans24GHz.append("=").append(result.frequency);
                            scans24GHz.append(",").append(result.level);
                            if (result.autoJoinStatus != 0) {
                                scans24GHz.append(",st=").append(result.autoJoinStatus);
                            }
                            if (result.numIpConfigFailures != 0) {
                                scans24GHz.append(",ipf=").append(result.numIpConfigFailures);
                            }
                            scans24GHz.append("}");
                            n24++;
                        }
                    }
                }
                visibility.append(" [");
                if (num24 > 0) {
                    visibility.append("(").append(num24).append(")");
                    if (n24 <= 4) {
                        if (scans24GHz != null) {
                            visibility.append(scans24GHz.toString());
                        }
                    } else {
                        visibility.append("max=").append(rssi24);
                        if (scans24GHz != null) {
                            visibility.append(",").append(scans24GHz.toString());
                        }
                    }
                }
                visibility.append(";");
                if (num5 > 0) {
                    visibility.append("(").append(num5).append(")");
                    if (n5 <= 4) {
                        if (scans5GHz != null) {
                            visibility.append(scans5GHz.toString());
                        }
                    } else {
                        visibility.append("max=").append(rssi5);
                        if (scans5GHz != null) {
                            visibility.append(",").append(scans5GHz.toString());
                        }
                    }
                }
                if (numBlackListed > 0)
                    visibility.append("!").append(numBlackListed);
                visibility.append("]");
            } else {
                if (mRssi != Integer.MAX_VALUE) {
                    visibility.append(" rssi=");
                    visibility.append(mRssi);
                    if (mScanResult != null) {
                        visibility.append(", f=");
                        visibility.append(mScanResult.frequency);
                    }
                }
            }
    
            return visibility.toString();
        }
    
        /**
         * Updates the title and summary; may indirectly call notifyChanged().
         */
        private void refresh() {
            setTitle(ssid);
    
            final Context context = getContext();
            updateIcon(getLevel(), context);
    
            // Force new summary
            setSummary(null);
    
            // Update to new summary
            StringBuilder summary = new StringBuilder();
    
            if (mState != null) { // This is the active connection
                summary.append(Summary.get(context, mState));
            } else if (mConfig != null && ((mConfig.status == WifiConfiguration.Status.DISABLED &&
                    mConfig.disableReason != WifiConfiguration.DISABLED_UNKNOWN_REASON)
                   || mConfig.autoJoinStatus
                    >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE)) {
                if (mConfig.autoJoinStatus
                        >= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) {
                    if (mConfig.disableReason == WifiConfiguration.DISABLED_DHCP_FAILURE) {
                        summary.append(context.getString(R.string.wifi_disabled_network_failure));
                    } else {
                        summary.append(context.getString(R.string.wifi_disabled_password_failure));
                    }
                } else {
                    switch (mConfig.disableReason) {
                        case WifiConfiguration.DISABLED_AUTH_FAILURE:
                            summary.append(context.getString(R.string.wifi_disabled_password_failure));
                            break;
                        case WifiConfiguration.DISABLED_DHCP_FAILURE:
                        case WifiConfiguration.DISABLED_DNS_FAILURE:
                            summary.append(context.getString(R.string.wifi_disabled_network_failure));
                            break;
                        case WifiConfiguration.DISABLED_UNKNOWN_REASON:
                        case WifiConfiguration.DISABLED_ASSOCIATION_REJECT:
                            summary.append(context.getString(R.string.wifi_disabled_generic));
                            break;
                    }
                }
            } else if (mRssi == Integer.MAX_VALUE) { // Wifi out of range
                summary.append(context.getString(R.string.wifi_not_in_range));
            } else { // In range, not disabled.
                if (mConfig != null) { // Is saved network
                    summary.append(context.getString(R.string.wifi_remembered));
                }
            }
    
            if (WifiSettings.mVerboseLogging > 0) {
                //add RSSI/band information for this config, what was seen up to 6 seconds ago
                //verbose WiFi Logging is only turned on thru developers settings
                if (mInfo != null && mState != null) { // This is the active connection
                    summary.append(" (f=" + Integer.toString(mInfo.getFrequency()) + ")");
                }
                summary.append(" " + getVisibilityStatus());
                if (mConfig != null && mConfig.autoJoinStatus > 0) {
                    summary.append(" (" + mConfig.autoJoinStatus);
                    if (mConfig.blackListTimestamp > 0) {
                        long now = System.currentTimeMillis();
                        long diff = (now - mConfig.blackListTimestamp)/1000;
                        long sec = diff%60; //seconds
                        long min = (diff/60)%60; //minutes
                        long hour = (min/60)%60; //hours
                        summary.append(", ");
                        if (hour > 0) summary.append(Long.toString(hour) + "h ");
                        summary.append( Long.toString(min) + "m ");
                        summary.append( Long.toString(sec) + "s ");
                    }
                    summary.append(")");
                }
            }
    
            if (summary.length() > 0) {
                setSummary(summary.toString());
            } else {
                showSummary = false;
            }
        }
    
        /**
         * Generate and save a default wifiConfiguration with common values.
         * Can only be called for unsecured networks.
         * @hide
         */
        protected void generateOpenNetworkConfig() {
            if (security != SECURITY_NONE)
                throw new IllegalStateException();
            if (mConfig != null)
                return;
            mConfig = new WifiConfiguration();
            mConfig.SSID = AccessPoint.convertToQuotedString(ssid);
            mConfig.allowedKeyManagement.set(KeyMgmt.NONE);
        }
    }
    
    
    /*
     * Copyright (C) 2010 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package com.android.settings.wifi;
    
    import com.android.settings.R;
    
    import android.app.AlertDialog;
    import android.content.Context;
    import android.content.DialogInterface;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    
    class WifiDialog extends AlertDialog implements WifiConfigUiBase {
        static final int BUTTON_SUBMIT = DialogInterface.BUTTON_POSITIVE;
        static final int BUTTON_FORGET = DialogInterface.BUTTON_NEUTRAL;
    
        private final boolean mEdit;
        private final DialogInterface.OnClickListener mListener;
        private final AccessPoint mAccessPoint;
    
        private View mView;
        private WifiConfigController mController;
        private boolean mHideSubmitButton;
    
        public WifiDialog(Context context, DialogInterface.OnClickListener listener,
                AccessPoint accessPoint, boolean edit, boolean hideSubmitButton) {
            this(context, listener, accessPoint, edit);
            mHideSubmitButton = hideSubmitButton;
        }
    
        public WifiDialog(Context context, DialogInterface.OnClickListener listener,
                AccessPoint accessPoint, boolean edit) {
            super(context);
            mEdit = edit;
            mListener = listener;
            mAccessPoint = accessPoint;
            mHideSubmitButton = false;
        }
    
        @Override
        public WifiConfigController getController() {
            return mController;
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            mView = getLayoutInflater().inflate(R.layout.wifi_dialog, null);
            setView(mView);
            setInverseBackgroundForced(true);
            mController = new WifiConfigController(this, mView, mAccessPoint, mEdit);
            super.onCreate(savedInstanceState);
    
            if (mHideSubmitButton) {
                mController.hideSubmitButton();
            } else {
                /* During creation, the submit button can be unavailable to determine
                 * visibility. Right after creation, update button visibility */
                mController.enableSubmitIfAppropriate();
            }
        }
    
        @Override
        public boolean isEdit() {
            return mEdit;
        }
    
        @Override
        public Button getSubmitButton() {
            return getButton(BUTTON_SUBMIT);
        }
    
        @Override
        public Button getForgetButton() {
            return getButton(BUTTON_FORGET);
        }
    
        @Override
        public Button getCancelButton() {
            return getButton(BUTTON_NEGATIVE);
        }
    
        @Override
        public void setSubmitButton(CharSequence text) {
            setButton(BUTTON_SUBMIT, text, mListener);
        }
    
        @Override
        public void setForgetButton(CharSequence text) {
            setButton(BUTTON_FORGET, text, mListener);
        }
    
        @Override
        public void setCancelButton(CharSequence text) {
            setButton(BUTTON_NEGATIVE, text, mListener);
        }
    }
    
    
    /*
     * Copyright (C) 2012 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package com.android.settings.wifi;
    
    import android.app.AlertDialog;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.net.NetworkInfo;
    import android.net.NetworkInfo.DetailedState;
    import android.net.wifi.WifiInfo;
    import android.net.wifi.WifiManager;
    import android.net.wifi.WpsInfo;
    import android.os.Bundle;
    import android.os.Handler;
    import android.view.View;
    import android.widget.Button;
    import android.widget.ProgressBar;
    import android.widget.TextView;
    
    import java.util.Timer;
    import java.util.TimerTask;
    
    import com.android.settings.R;
    
    
    /**
     * Dialog to show WPS progress.
     */
    public class WpsDialog extends AlertDialog {
    
        private final static String TAG = "WpsDialog";
        private static final String DIALOG_STATE = "android:dialogState";
        private static final String DIALOG_MSG_STRING = "android:dialogMsg";
    
        private View mView;
        private TextView mTextView;
        private ProgressBar mTimeoutBar;
        private ProgressBar mProgressBar;
        private Button mButton;
        private Timer mTimer;
    
        private static final int WPS_TIMEOUT_S = 120;
    
        private WifiManager mWifiManager;
        private WifiManager.WpsCallback mWpsListener;
        private int mWpsSetup;
    
        private final IntentFilter mFilter;
        private BroadcastReceiver mReceiver;
    
        private Context mContext;
        private Handler mHandler = new Handler();
        private String mMsgString = "";
    
        private enum DialogState {
            WPS_INIT,
            WPS_START,
            WPS_COMPLETE,
            CONNECTED, //WPS + IP config is done
            WPS_FAILED
        }
        DialogState mDialogState = DialogState.WPS_INIT;
    
        public WpsDialog(Context context, int wpsSetup) {
            super(context);
            mContext = context;
            mWpsSetup = wpsSetup;
    
            class WpsListener extends WifiManager.WpsCallback {
    
                public void onStarted(String pin) {
                    if (pin != null) {
                        updateDialog(DialogState.WPS_START, String.format(
                                mContext.getString(R.string.wifi_wps_onstart_pin), pin));
                    } else {
                        updateDialog(DialogState.WPS_START, mContext.getString(
                                R.string.wifi_wps_onstart_pbc));
                    }
                }
    
                public void onSucceeded() {
                    updateDialog(DialogState.WPS_COMPLETE,
                            mContext.getString(R.string.wifi_wps_complete));
                }
    
                public void onFailed(int reason) {
                    String msg;
                    switch (reason) {
                        case WifiManager.WPS_OVERLAP_ERROR:
                            msg = mContext.getString(R.string.wifi_wps_failed_overlap);
                            break;
                        case WifiManager.WPS_WEP_PROHIBITED:
                            msg = mContext.getString(R.string.wifi_wps_failed_wep);
                            break;
                        case WifiManager.WPS_TKIP_ONLY_PROHIBITED:
                            msg = mContext.getString(R.string.wifi_wps_failed_tkip);
                            break;
                        case WifiManager.IN_PROGRESS:
                            msg = mContext.getString(R.string.wifi_wps_in_progress);
                            break;
                        default:
                            msg = mContext.getString(R.string.wifi_wps_failed_generic);
                            break;
                    }
                    updateDialog(DialogState.WPS_FAILED, msg);
                }
            }
    
            mWpsListener = new WpsListener();
    
    
            mFilter = new IntentFilter();
            mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
            mReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    handleEvent(context, intent);
                }
            };
            setCanceledOnTouchOutside(false);
        }
    
        @Override
        public Bundle onSaveInstanceState () {
            Bundle bundle  = super.onSaveInstanceState();
            bundle.putString(DIALOG_STATE, mDialogState.toString());
            bundle.putString(DIALOG_MSG_STRING, mMsgString.toString());
            return bundle;
        }
    
        @Override
        public void onRestoreInstanceState(Bundle savedInstanceState) {
            if (savedInstanceState != null) {
                super.onRestoreInstanceState(savedInstanceState);
                DialogState dialogState = mDialogState.valueOf(savedInstanceState.getString(DIALOG_STATE));
                String msg = savedInstanceState.getString(DIALOG_MSG_STRING);
                updateDialog(dialogState, msg);
            }
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            mView = getLayoutInflater().inflate(R.layout.wifi_wps_dialog, null);
    
            mTextView = (TextView) mView.findViewById(R.id.wps_dialog_txt);
            mTextView.setText(R.string.wifi_wps_setup_msg);
    
            mTimeoutBar = ((ProgressBar) mView.findViewById(R.id.wps_timeout_bar));
            mTimeoutBar.setMax(WPS_TIMEOUT_S);
            mTimeoutBar.setProgress(0);
    
            mProgressBar = ((ProgressBar) mView.findViewById(R.id.wps_progress_bar));
            mProgressBar.setVisibility(View.GONE);
    
            mButton = ((Button) mView.findViewById(R.id.wps_dialog_btn));
            mButton.setText(R.string.wifi_cancel);
            mButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    dismiss();
                }
            });
    
            mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
    
            setView(mView);
            super.onCreate(savedInstanceState);
        }
    
        @Override
        protected void onStart() {
            /*
             * increment timeout bar per second.
             */
            mTimer = new Timer(false);
            mTimer.schedule(new TimerTask() {
                @Override
                public void run() {
                    mHandler.post(new Runnable() {
    
                        @Override
                        public void run() {
                            mTimeoutBar.incrementProgressBy(1);
                        }
                    });
                }
            }, 1000, 1000);
    
            mContext.registerReceiver(mReceiver, mFilter);
    
            WpsInfo wpsConfig = new WpsInfo();
            wpsConfig.setup = mWpsSetup;
            mWifiManager.startWps(wpsConfig, mWpsListener);
        }
    
        @Override
        protected void onStop() {
            if (mDialogState != DialogState.WPS_COMPLETE) {
                mWifiManager.cancelWps(null);
            }
    
            if (mReceiver != null) {
                mContext.unregisterReceiver(mReceiver);
                mReceiver = null;
            }
    
            if (mTimer != null) {
                mTimer.cancel();
            }
        }
    
        private void updateDialog(final DialogState state, final String msg) {
            if (mDialogState.ordinal() >= state.ordinal()) {
                //ignore.
                return;
            }
            mDialogState = state;
            mMsgString = msg;
    
            mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        switch(state) {
                            case WPS_COMPLETE:
                                mTimeoutBar.setVisibility(View.GONE);
                                mProgressBar.setVisibility(View.VISIBLE);
                                break;
                            case CONNECTED:
                            case WPS_FAILED:
                                mButton.setText(mContext.getString(R.string.dlg_ok));
                                mTimeoutBar.setVisibility(View.GONE);
                                mProgressBar.setVisibility(View.GONE);
                                if (mReceiver != null) {
                                    mContext.unregisterReceiver(mReceiver);
                                    mReceiver = null;
                                }
                                break;
                        }
                        mTextView.setText(msg);
                    }
                });
       }
    
        private void handleEvent(Context context, Intent intent) {
            String action = intent.getAction();
            if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
                NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
                        WifiManager.EXTRA_NETWORK_INFO);
                final NetworkInfo.DetailedState state = info.getDetailedState();
                if (state == DetailedState.CONNECTED &&
                        mDialogState == DialogState.WPS_COMPLETE) {
                    WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
                    if (wifiInfo != null) {
                        String msg = String.format(mContext.getString(
                                R.string.wifi_wps_connected), wifiInfo.getSSID());
                        updateDialog(DialogState.CONNECTED, msg);
                    }
                }
            }
        }
    
    }
    
    
    /*
     * Copyright (C) 2014 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package com.android.settings.wifi;
    
    import android.app.Activity;
    import android.app.AlertDialog;
    import android.content.Context;
    import android.content.DialogInterface;
    import android.net.wifi.WifiManager;
    import android.nfc.FormatException;
    import android.nfc.NdefMessage;
    import android.nfc.NdefRecord;
    import android.nfc.NfcAdapter;
    import android.nfc.Tag;
    import android.nfc.tech.Ndef;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.PowerManager;
    import android.text.Editable;
    import android.text.InputType;
    import android.text.TextWatcher;
    import android.util.Log;
    import android.view.Gravity;
    import android.view.View;
    import android.view.inputmethod.InputMethodManager;
    import android.widget.Button;
    import android.widget.CheckBox;
    import android.widget.CompoundButton;
    import android.widget.LinearLayout;
    import android.widget.ProgressBar;
    import android.widget.TextView;
    
    import com.android.settings.R;
    
    import java.io.IOException;
    
    class WriteWifiConfigToNfcDialog extends AlertDialog
            implements TextWatcher, View.OnClickListener, CompoundButton.OnCheckedChangeListener {
    
        private static final String NFC_TOKEN_MIME_TYPE = "application/vnd.wfa.wsc";
    
        private static final String TAG = WriteWifiConfigToNfcDialog.class.getName().toString();
        private static final String PASSWORD_FORMAT = "102700%s%s";
        private static final int HEX_RADIX = 16;
        private static final char[] hexArray = "0123456789ABCDEF".toCharArray();
    
        private final PowerManager.WakeLock mWakeLock;
    
        private AccessPoint mAccessPoint;
        private View mView;
        private Button mSubmitButton;
        private Button mCancelButton;
        private Handler mOnTextChangedHandler;
        private TextView mPasswordView;
        private TextView mLabelView;
        private CheckBox mPasswordCheckBox;
        private ProgressBar mProgressBar;
        private WifiManager mWifiManager;
        private String mWpsNfcConfigurationToken;
        private Context mContext;
    
        WriteWifiConfigToNfcDialog(Context context, AccessPoint accessPoint,
                WifiManager wifiManager) {
            super(context);
    
            mContext = context;
            mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE))
                    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WriteWifiConfigToNfcDialog:wakeLock");
            mAccessPoint = accessPoint;
            mOnTextChangedHandler = new Handler();
            mWifiManager = wifiManager;
        }
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            mView = getLayoutInflater().inflate(R.layout.write_wifi_config_to_nfc, null);
    
            setView(mView);
            setInverseBackgroundForced(true);
            setTitle(R.string.setup_wifi_nfc_tag);
            setCancelable(true);
            setButton(DialogInterface.BUTTON_NEUTRAL,
                    mContext.getResources().getString(R.string.write_tag), (OnClickListener) null);
            setButton(DialogInterface.BUTTON_NEGATIVE,
                    mContext.getResources().getString(com.android.internal.R.string.cancel),
                    (OnClickListener) null);
    
            mPasswordView = (TextView) mView.findViewById(R.id.password);
            mLabelView = (TextView) mView.findViewById(R.id.password_label);
            mPasswordView.addTextChangedListener(this);
            mPasswordCheckBox = (CheckBox) mView.findViewById(R.id.show_password);
            mPasswordCheckBox.setOnCheckedChangeListener(this);
            mProgressBar = (ProgressBar) mView.findViewById(R.id.progress_bar);
    
            super.onCreate(savedInstanceState);
    
            mSubmitButton = getButton(DialogInterface.BUTTON_NEUTRAL);
            mSubmitButton.setOnClickListener(this);
            mSubmitButton.setEnabled(false);
    
            mCancelButton = getButton(DialogInterface.BUTTON_NEGATIVE);
        }
    
        @Override
        public void onClick(View v) {
            mWakeLock.acquire();
    
            String password = mPasswordView.getText().toString();
            String wpsNfcConfigurationToken
                    = mWifiManager.getWpsNfcConfigurationToken(mAccessPoint.networkId);
            String passwordHex = byteArrayToHexString(password.getBytes());
    
            String passwordLength = password.length() >= HEX_RADIX
                    ? Integer.toString(password.length(), HEX_RADIX)
                    : "0" + Character.forDigit(password.length(), HEX_RADIX);
    
            passwordHex = String.format(PASSWORD_FORMAT, passwordLength, passwordHex).toUpperCase();
    
            if (wpsNfcConfigurationToken.contains(passwordHex)) {
                mWpsNfcConfigurationToken = wpsNfcConfigurationToken;
    
                Activity activity = getOwnerActivity();
                NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(activity);
    
                nfcAdapter.enableReaderMode(activity, new NfcAdapter.ReaderCallback() {
                    @Override
                    public void onTagDiscovered(Tag tag) {
                        handleWriteNfcEvent(tag);
                    }
                }, NfcAdapter.FLAG_READER_NFC_A |
                        NfcAdapter.FLAG_READER_NFC_B |
                        NfcAdapter.FLAG_READER_NFC_BARCODE |
                        NfcAdapter.FLAG_READER_NFC_F |
                        NfcAdapter.FLAG_READER_NFC_V,
                        null);
    
                mPasswordView.setVisibility(View.GONE);
                mPasswordCheckBox.setVisibility(View.GONE);
                mSubmitButton.setVisibility(View.GONE);
                InputMethodManager imm = (InputMethodManager)
                        getOwnerActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(mPasswordView.getWindowToken(), 0);
    
                mLabelView.setText(R.string.status_awaiting_tap);
    
                mView.findViewById(R.id.password_layout).setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
                mProgressBar.setVisibility(View.VISIBLE);
            } else {
                mLabelView.setText(R.string.status_invalid_password);
            }
        }
    
        private void handleWriteNfcEvent(Tag tag) {
            Ndef ndef = Ndef.get(tag);
    
            if (ndef != null) {
                if (ndef.isWritable()) {
                    NdefRecord record = NdefRecord.createMime(
                            NFC_TOKEN_MIME_TYPE,
                            hexStringToByteArray(mWpsNfcConfigurationToken));
                    try {
                        ndef.connect();
                        ndef.writeNdefMessage(new NdefMessage(record));
                        getOwnerActivity().runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                mProgressBar.setVisibility(View.GONE);
                            }
                        });
                        setViewText(mLabelView, R.string.status_write_success);
                        setViewText(mCancelButton, com.android.internal.R.string.done_label);
                    } catch (IOException e) {
                        setViewText(mLabelView, R.string.status_failed_to_write);
                        Log.e(TAG, "Unable to write Wi-Fi config to NFC tag.", e);
                        return;
                    } catch (FormatException e) {
                        setViewText(mLabelView, R.string.status_failed_to_write);
                        Log.e(TAG, "Unable to write Wi-Fi config to NFC tag.", e);
                        return;
                    }
                } else {
                    setViewText(mLabelView, R.string.status_tag_not_writable);
                    Log.e(TAG, "Tag is not writable");
                }
            } else {
                setViewText(mLabelView, R.string.status_tag_not_writable);
                Log.e(TAG, "Tag does not support NDEF");
            }
        }
    
        @Override
        public void dismiss() {
            if (mWakeLock.isHeld()) {
                mWakeLock.release();
            }
    
            super.dismiss();
        }
    
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            mOnTextChangedHandler.post(new Runnable() {
                @Override
                public void run() {
                    enableSubmitIfAppropriate();
                }
            });
        }
    
        private void enableSubmitIfAppropriate() {
    
            if (mPasswordView != null) {
                if (mAccessPoint.security == AccessPoint.SECURITY_WEP) {
                    mSubmitButton.setEnabled(mPasswordView.length() > 0);
                } else if (mAccessPoint.security == AccessPoint.SECURITY_PSK) {
                    mSubmitButton.setEnabled(mPasswordView.length() >= 8);
                }
            } else {
                mSubmitButton.setEnabled(false);
            }
    
        }
    
        private void setViewText(final TextView view, final int resid) {
            getOwnerActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    view.setText(resid);
                }
            });
        }
    
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            mPasswordView.setInputType(
                    InputType.TYPE_CLASS_TEXT |
                    (isChecked
                            ? InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
                            : InputType.TYPE_TEXT_VARIATION_PASSWORD));
        }
    
        private static byte[] hexStringToByteArray(String s) {
            int len = s.length();
            byte[] data = new byte[len / 2];
    
            for (int i = 0; i < len; i += 2) {
                data[i / 2] = (byte) ((Character.digit(s.charAt(i), HEX_RADIX) << 4)
                        + Character.digit(s.charAt(i + 1), HEX_RADIX));
            }
    
            return data;
        }
    
        private static String byteArrayToHexString(byte[] bytes) {
            char[] hexChars = new char[bytes.length * 2];
            for ( int j = 0; j < bytes.length; j++ ) {
                int v = bytes[j] & 0xFF;
                hexChars[j * 2] = hexArray[v >>> 4];
                hexChars[j * 2 + 1] = hexArray[v & 0x0F];
            }
            return new String(hexChars);
        }
    
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
    
        @Override
        public void afterTextChanged(Editable s) {}
    }
    
    
    /*
     * Copyright (C) 2010 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package com.android.settings.wifi;
    
    import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
    
    import android.app.ActivityManager;
    import android.content.Context;
    import android.content.res.Resources;
    import android.net.IpConfiguration;
    import android.net.IpConfiguration.IpAssignment;
    import android.net.IpConfiguration.ProxySettings;
    import android.net.LinkAddress;
    import android.net.NetworkInfo.DetailedState;
    import android.net.NetworkUtils;
    import android.net.ProxyInfo;
    import android.net.RouteInfo;
    import android.net.StaticIpConfiguration;
    import android.net.Uri;
    import android.net.wifi.WifiConfiguration;
    import android.net.wifi.WifiConfiguration.AuthAlgorithm;
    import android.net.wifi.WifiConfiguration.KeyMgmt;
    import android.net.wifi.WifiEnterpriseConfig;
    import android.net.wifi.WifiEnterpriseConfig.Eap;
    import android.net.wifi.WifiEnterpriseConfig.Phase2;
    import android.net.wifi.WifiInfo;
    import android.os.Handler;
    import android.os.UserHandle;
    import android.security.Credentials;
    import android.security.KeyStore;
    import android.text.Editable;
    import android.text.InputType;
    import android.text.TextWatcher;
    import android.text.TextUtils;
    import android.util.Log;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.AdapterView;
    import android.widget.ArrayAdapter;
    import android.widget.Button;
    import android.widget.CheckBox;
    import android.widget.CompoundButton;
    import android.widget.CompoundButton.OnCheckedChangeListener;
    import android.widget.EditText;
    import android.widget.Spinner;
    import android.widget.TextView;
    
    import com.android.settings.ProxySelector;
    import com.android.settings.R;
    
    import java.net.InetAddress;
    import java.net.Inet4Address;
    import java.util.Iterator;
    
    /**
     * The class for allowing UIs like {@link WifiDialog} and {@link WifiConfigUiBase} to
     * share the logic for controlling buttons, text fields, etc.
     */
    public class WifiConfigController implements TextWatcher,
           AdapterView.OnItemSelectedListener, OnCheckedChangeListener {
        private static final String TAG = "WifiConfigController";
    
        private final WifiConfigUiBase mConfigUi;
        private final View mView;
        private final AccessPoint mAccessPoint;
    
        /* This value comes from "wifi_ip_settings" resource array */
        private static final int DHCP = 0;
        private static final int STATIC_IP = 1;
    
        /* These values come from "wifi_proxy_settings" resource array */
        public static final int PROXY_NONE = 0;
        public static final int PROXY_STATIC = 1;
        public static final int PROXY_PAC = 2;
    
        /* These values come from "wifi_eap_method" resource array */
        public static final int WIFI_EAP_METHOD_PEAP = 0;
        public static final int WIFI_EAP_METHOD_TLS  = 1;
        public static final int WIFI_EAP_METHOD_TTLS = 2;
        public static final int WIFI_EAP_METHOD_PWD  = 3;
    
        /* These values come from "wifi_peap_phase2_entries" resource array */
        public static final int WIFI_PEAP_PHASE2_NONE       = 0;
        public static final int WIFI_PEAP_PHASE2_MSCHAPV2   = 1;
        public static final int WIFI_PEAP_PHASE2_GTC        = 2;
    
        /* Phase2 methods supported by PEAP are limited */
        private final ArrayAdapter<String> PHASE2_PEAP_ADAPTER;
        /* Full list of phase2 methods */
        private final ArrayAdapter<String> PHASE2_FULL_ADAPTER;
    
        // True when this instance is used in SetupWizard XL context.
        private final boolean mInXlSetupWizard;
    
        private final Handler mTextViewChangedHandler;
    
        // e.g. AccessPoint.SECURITY_NONE
        private int mAccessPointSecurity;
        private TextView mPasswordView;
    
        private String unspecifiedCert = "unspecified";
        private static final int unspecifiedCertIndex = 0;
    
        private Spinner mSecuritySpinner;
        private Spinner mEapMethodSpinner;
        private Spinner mEapCaCertSpinner;
        private Spinner mPhase2Spinner;
        // Associated with mPhase2Spinner, one of PHASE2_FULL_ADAPTER or PHASE2_PEAP_ADAPTER
        private ArrayAdapter<String> mPhase2Adapter;
        private Spinner mEapUserCertSpinner;
        private TextView mEapIdentityView;
        private TextView mEapAnonymousView;
    
        private Spinner mIpSettingsSpinner;
        private TextView mIpAddressView;
        private TextView mGatewayView;
        private TextView mNetworkPrefixLengthView;
        private TextView mDns1View;
        private TextView mDns2View;
    
        private Spinner mProxySettingsSpinner;
        private TextView mProxyHostView;
        private TextView mProxyPortView;
        private TextView mProxyExclusionListView;
        private TextView mProxyPacView;
    
        private IpAssignment mIpAssignment = IpAssignment.UNASSIGNED;
        private ProxySettings mProxySettings = ProxySettings.UNASSIGNED;
        private ProxyInfo mHttpProxy = null;
        private StaticIpConfiguration mStaticIpConfiguration = null;
    
        private String[] mLevels;
        private boolean mEdit;
        private TextView mSsidView;
    
        private Context mContext;
    
        public WifiConfigController(
                WifiConfigUiBase parent, View view, AccessPoint accessPoint, boolean edit) {
            mConfigUi = parent;
            mInXlSetupWizard = (parent instanceof WifiConfigUiForSetupWizardXL);
    
            mView = view;
            mAccessPoint = accessPoint;
            mAccessPointSecurity = (accessPoint == null) ? AccessPoint.SECURITY_NONE :
                    accessPoint.security;
            mEdit = edit;
    
            mTextViewChangedHandler = new Handler();
            mContext = mConfigUi.getContext();
            final Resources res = mContext.getResources();
    
            mLevels = res.getStringArray(R.array.wifi_signal);
            PHASE2_PEAP_ADAPTER = new ArrayAdapter<String>(
                mContext, android.R.layout.simple_spinner_item,
                res.getStringArray(R.array.wifi_peap_phase2_entries));
            PHASE2_PEAP_ADAPTER.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    
            PHASE2_FULL_ADAPTER = new ArrayAdapter<String>(
                    mContext, android.R.layout.simple_spinner_item,
                    res.getStringArray(R.array.wifi_phase2_entries));
            PHASE2_FULL_ADAPTER.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    
            unspecifiedCert = mContext.getString(R.string.wifi_unspecified);
            mIpSettingsSpinner = (Spinner) mView.findViewById(R.id.ip_settings);
            mIpSettingsSpinner.setOnItemSelectedListener(this);
            mProxySettingsSpinner = (Spinner) mView.findViewById(R.id.proxy_settings);
            mProxySettingsSpinner.setOnItemSelectedListener(this);
    
            if (mAccessPoint == null) { // new network
                mConfigUi.setTitle(R.string.wifi_add_network);
    
                mSsidView = (TextView) mView.findViewById(R.id.ssid);
                mSsidView.addTextChangedListener(this);
                mSecuritySpinner = ((Spinner) mView.findViewById(R.id.security));
                mSecuritySpinner.setOnItemSelectedListener(this);
                if (mInXlSetupWizard) {
                    mView.findViewById(R.id.type_ssid).setVisibility(View.VISIBLE);
                    mView.findViewById(R.id.type_security).setVisibility(View.VISIBLE);
                    // We want custom layout. The content must be same as the other cases.
    
                    ArrayAdapter<String> adapter = new ArrayAdapter<String>(mContext,
                            R.layout.wifi_setup_custom_list_item_1, android.R.id.text1,
                            res.getStringArray(R.array.wifi_security_no_eap));
                    mSecuritySpinner.setAdapter(adapter);
                } else {
                    mView.findViewById(R.id.type).setVisibility(View.VISIBLE);
                }
    
                showIpConfigFields();
                showProxyFields();
                mView.findViewById(R.id.wifi_advanced_toggle).setVisibility(View.VISIBLE);
                ((CheckBox)mView.findViewById(R.id.wifi_advanced_togglebox))
                        .setOnCheckedChangeListener(this);
    
    
                mConfigUi.setSubmitButton(res.getString(R.string.wifi_save));
            } else {
                mConfigUi.setTitle(mAccessPoint.ssid);
    
                ViewGroup group = (ViewGroup) mView.findViewById(R.id.info);
    
                boolean showAdvancedFields = false;
                if (mAccessPoint.networkId != INVALID_NETWORK_ID) {
                    WifiConfiguration config = mAccessPoint.getConfig();
                    if (config.getIpAssignment() == IpAssignment.STATIC) {
                        mIpSettingsSpinner.setSelection(STATIC_IP);
                        showAdvancedFields = true;
                        // Display IP address.
                        StaticIpConfiguration staticConfig = config.getStaticIpConfiguration();
                        if (staticConfig != null && staticConfig.ipAddress != null) {
                            addRow(group, R.string.wifi_ip_address,
                               staticConfig.ipAddress.getAddress().getHostAddress());
                        }
                    } else {
                        mIpSettingsSpinner.setSelection(DHCP);
                    }
    
    
                    if (config.getProxySettings() == ProxySettings.STATIC) {
                        mProxySettingsSpinner.setSelection(PROXY_STATIC);
                        showAdvancedFields = true;
                    } else if (config.getProxySettings() == ProxySettings.PAC) {
                        mProxySettingsSpinner.setSelection(PROXY_PAC);
                        showAdvancedFields = true;
                    } else {
                        mProxySettingsSpinner.setSelection(PROXY_NONE);
                    }
                }
    
                if (mAccessPoint.networkId == INVALID_NETWORK_ID || mEdit) {
                    showSecurityFields();
                    showIpConfigFields();
                    showProxyFields();
                    mView.findViewById(R.id.wifi_advanced_toggle).setVisibility(View.VISIBLE);
                    ((CheckBox)mView.findViewById(R.id.wifi_advanced_togglebox))
                        .setOnCheckedChangeListener(this);
                    if (showAdvancedFields) {
                        ((CheckBox)mView.findViewById(R.id.wifi_advanced_togglebox)).setChecked(true);
                        mView.findViewById(R.id.wifi_advanced_fields).setVisibility(View.VISIBLE);
                    }
                }
    
                if (mEdit) {
                    mConfigUi.setSubmitButton(res.getString(R.string.wifi_save));
                } else {
                    final DetailedState state = mAccessPoint.getState();
                    final String signalLevel = getSignalString();
    
                    if (state == null && signalLevel != null) {
                        mConfigUi.setSubmitButton(res.getString(R.string.wifi_connect));
                    } else {
                        if (state != null) {
                            addRow(group, R.string.wifi_status, Summary.get(mConfigUi.getContext(),
                                    state));
                        }
    
                        if (signalLevel != null) {
                            addRow(group, R.string.wifi_signal, signalLevel);
                        }
    
                        WifiInfo info = mAccessPoint.getInfo();
                        if (info != null && info.getLinkSpeed() != -1) {
                            addRow(group, R.string.wifi_speed, info.getLinkSpeed()
                                    + WifiInfo.LINK_SPEED_UNITS);
                        }
    
                        if (info != null && info.getFrequency() != -1) {
                            final int frequency = info.getFrequency();
                            String band = null;
    
                            if (frequency >= AccessPoint.LOWER_FREQ_24GHZ
                                    && frequency < AccessPoint.HIGHER_FREQ_24GHZ) {
                                band = res.getString(R.string.wifi_band_24ghz);
                            } else if (frequency >= AccessPoint.LOWER_FREQ_5GHZ
                                    && frequency < AccessPoint.HIGHER_FREQ_5GHZ) {
                                band = res.getString(R.string.wifi_band_5ghz);
                            } else {
                                Log.e(TAG, "Unexpected frequency " + frequency);
                            }
                            if (band != null) {
                                addRow(group, R.string.wifi_frequency, band);
                            }
                        }
    
                        addRow(group, R.string.wifi_security, mAccessPoint.getSecurityString(false));
                        mView.findViewById(R.id.ip_fields).setVisibility(View.GONE);
                    }
                    if (mAccessPoint.networkId != INVALID_NETWORK_ID
                            && ActivityManager.getCurrentUser() == UserHandle.USER_OWNER) {
                        mConfigUi.setForgetButton(res.getString(R.string.wifi_forget));
                    }
                }
            }
    
            if (mEdit || (mAccessPoint.getState() == null && mAccessPoint.getLevel() != -1)){
                mConfigUi.setCancelButton(res.getString(R.string.wifi_cancel));
            }else{
                mConfigUi.setCancelButton(res.getString(R.string.wifi_display_options_done));
            }
            if (mConfigUi.getSubmitButton() != null) {
                enableSubmitIfAppropriate();
            }
        }
    
        private void addRow(ViewGroup group, int name, String value) {
            View row = mConfigUi.getLayoutInflater().inflate(R.layout.wifi_dialog_row, group, false);
            ((TextView) row.findViewById(R.id.name)).setText(name);
            ((TextView) row.findViewById(R.id.value)).setText(value);
            group.addView(row);
        }
    
        private String getSignalString(){
            final int level = mAccessPoint.getLevel();
    
            return (level > -1 && level < mLevels.length) ? mLevels[level] : null;
        }
    
        void hideSubmitButton() {
            Button submit = mConfigUi.getSubmitButton();
            if (submit == null) return;
    
            submit.setVisibility(View.GONE);
        }
    
        /* show submit button if password, ip and proxy settings are valid */
        void enableSubmitIfAppropriate() {
            Button submit = mConfigUi.getSubmitButton();
            if (submit == null) return;
    
            boolean enabled = false;
            boolean passwordInvalid = false;
    
            if (mPasswordView != null &&
                ((mAccessPointSecurity == AccessPoint.SECURITY_WEP && mPasswordView.length() == 0) ||
                (mAccessPointSecurity == AccessPoint.SECURITY_PSK && mPasswordView.length() < 8))) {
                passwordInvalid = true;
            }
    
            if ((mSsidView != null && mSsidView.length() == 0) ||
                ((mAccessPoint == null || mAccessPoint.networkId == INVALID_NETWORK_ID) &&
                passwordInvalid)) {
                enabled = false;
            } else {
                if (ipAndProxyFieldsAreValid()) {
                    enabled = true;
                } else {
                    enabled = false;
                }
            }
            submit.setEnabled(enabled);
        }
    
        /* package */ WifiConfiguration getConfig() {
            if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID && !mEdit) {
                return null;
            }
    
            WifiConfiguration config = new WifiConfiguration();
    
            if (mAccessPoint == null) {
                config.SSID = AccessPoint.convertToQuotedString(
                        mSsidView.getText().toString());
                // If the user adds a network manually, assume that it is hidden.
                config.hiddenSSID = true;
            } else if (mAccessPoint.networkId == INVALID_NETWORK_ID) {
                config.SSID = AccessPoint.convertToQuotedString(
                        mAccessPoint.ssid);
            } else {
                config.networkId = mAccessPoint.networkId;
            }
    
            switch (mAccessPointSecurity) {
                case AccessPoint.SECURITY_NONE:
                    config.allowedKeyManagement.set(KeyMgmt.NONE);
                    break;
    
                case AccessPoint.SECURITY_WEP:
                    config.allowedKeyManagement.set(KeyMgmt.NONE);
                    config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
                    config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
                    if (mPasswordView.length() != 0) {
                        int length = mPasswordView.length();
                        String password = mPasswordView.getText().toString();
                        // WEP-40, WEP-104, and 256-bit WEP (WEP-232?)
                        if ((length == 10 || length == 26 || length == 58) &&
                                password.matches("[0-9A-Fa-f]*")) {
                            config.wepKeys[0] = password;
                        } else {
                            config.wepKeys[0] = '"' + password + '"';
                        }
                    }
                    break;
    
                case AccessPoint.SECURITY_PSK:
                    config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
                    if (mPasswordView.length() != 0) {
                        String password = mPasswordView.getText().toString();
                        if (password.matches("[0-9A-Fa-f]{64}")) {
                            config.preSharedKey = password;
                        } else {
                            config.preSharedKey = '"' + password + '"';
                        }
                    }
                    break;
    
                case AccessPoint.SECURITY_EAP:
                    config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
                    config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
                    config.enterpriseConfig = new WifiEnterpriseConfig();
                    int eapMethod = mEapMethodSpinner.getSelectedItemPosition();
                    int phase2Method = mPhase2Spinner.getSelectedItemPosition();
                    config.enterpriseConfig.setEapMethod(eapMethod);
                    switch (eapMethod) {
                        case Eap.PEAP:
                            // PEAP supports limited phase2 values
                            // Map the index from the PHASE2_PEAP_ADAPTER to the one used
                            // by the API which has the full list of PEAP methods.
                            switch(phase2Method) {
                                case WIFI_PEAP_PHASE2_NONE:
                                    config.enterpriseConfig.setPhase2Method(Phase2.NONE);
                                    break;
                                case WIFI_PEAP_PHASE2_MSCHAPV2:
                                    config.enterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
                                    break;
                                case WIFI_PEAP_PHASE2_GTC:
                                    config.enterpriseConfig.setPhase2Method(Phase2.GTC);
                                    break;
                                default:
                                    Log.e(TAG, "Unknown phase2 method" + phase2Method);
                                    break;
                            }
                            break;
                        default:
                            // The default index from PHASE2_FULL_ADAPTER maps to the API
                            config.enterpriseConfig.setPhase2Method(phase2Method);
                            break;
                    }
                    String caCert = (String) mEapCaCertSpinner.getSelectedItem();
                    if (caCert.equals(unspecifiedCert)) caCert = "";
                    config.enterpriseConfig.setCaCertificateAlias(caCert);
                    String clientCert = (String) mEapUserCertSpinner.getSelectedItem();
                    if (clientCert.equals(unspecifiedCert)) clientCert = "";
                    config.enterpriseConfig.setClientCertificateAlias(clientCert);
                    config.enterpriseConfig.setIdentity(mEapIdentityView.getText().toString());
                    config.enterpriseConfig.setAnonymousIdentity(
                            mEapAnonymousView.getText().toString());
    
                    if (mPasswordView.isShown()) {
                        // For security reasons, a previous password is not displayed to user.
                        // Update only if it has been changed.
                        if (mPasswordView.length() > 0) {
                            config.enterpriseConfig.setPassword(mPasswordView.getText().toString());
                        }
                    } else {
                        // clear password
                        config.enterpriseConfig.setPassword(mPasswordView.getText().toString());
                    }
                    break;
                default:
                    return null;
            }
    
            config.setIpConfiguration(
                    new IpConfiguration(mIpAssignment, mProxySettings,
                                        mStaticIpConfiguration, mHttpProxy));
    
            return config;
        }
    
        private boolean ipAndProxyFieldsAreValid() {
            mIpAssignment = (mIpSettingsSpinner != null &&
                    mIpSettingsSpinner.getSelectedItemPosition() == STATIC_IP) ?
                    IpAssignment.STATIC : IpAssignment.DHCP;
    
            if (mIpAssignment == IpAssignment.STATIC) {
                mStaticIpConfiguration = new StaticIpConfiguration();
                int result = validateIpConfigFields(mStaticIpConfiguration);
                if (result != 0) {
                    return false;
                }
            }
    
            final int selectedPosition = mProxySettingsSpinner.getSelectedItemPosition();
            mProxySettings = ProxySettings.NONE;
            mHttpProxy = null;
            if (selectedPosition == PROXY_STATIC && mProxyHostView != null) {
                mProxySettings = ProxySettings.STATIC;
                String host = mProxyHostView.getText().toString();
                String portStr = mProxyPortView.getText().toString();
                String exclusionList = mProxyExclusionListView.getText().toString();
                int port = 0;
                int result = 0;
                try {
                    port = Integer.parseInt(portStr);
                    result = ProxySelector.validate(host, portStr, exclusionList);
                } catch (NumberFormatException e) {
                    result = R.string.proxy_error_invalid_port;
                }
                if (result == 0) {
                    mHttpProxy = new ProxyInfo(host, port, exclusionList);
                } else {
                    return false;
                }
            } else if (selectedPosition == PROXY_PAC && mProxyPacView != null) {
                mProxySettings = ProxySettings.PAC;
                CharSequence uriSequence = mProxyPacView.getText();
                if (TextUtils.isEmpty(uriSequence)) {
                    return false;
                }
                Uri uri = Uri.parse(uriSequence.toString());
                if (uri == null) {
                    return false;
                }
                mHttpProxy = new ProxyInfo(uri);
            }
            return true;
        }
    
        private Inet4Address getIPv4Address(String text) {
            try {
                return (Inet4Address) NetworkUtils.numericToInetAddress(text);
            } catch (IllegalArgumentException|ClassCastException e) {
                return null;
            }
        }
    
        private int validateIpConfigFields(StaticIpConfiguration staticIpConfiguration) {
            if (mIpAddressView == null) return 0;
    
            String ipAddr = mIpAddressView.getText().toString();
            if (TextUtils.isEmpty(ipAddr)) return R.string.wifi_ip_settings_invalid_ip_address;
    
            Inet4Address inetAddr = getIPv4Address(ipAddr);
            if (inetAddr == null) {
                return R.string.wifi_ip_settings_invalid_ip_address;
            }
    
            int networkPrefixLength = -1;
            try {
                networkPrefixLength = Integer.parseInt(mNetworkPrefixLengthView.getText().toString());
                if (networkPrefixLength < 0 || networkPrefixLength > 32) {
                    return R.string.wifi_ip_settings_invalid_network_prefix_length;
                }
                staticIpConfiguration.ipAddress = new LinkAddress(inetAddr, networkPrefixLength);
            } catch (NumberFormatException e) {
                // Set the hint as default after user types in ip address
                mNetworkPrefixLengthView.setText(mConfigUi.getContext().getString(
                        R.string.wifi_network_prefix_length_hint));
            }
    
            String gateway = mGatewayView.getText().toString();
            if (TextUtils.isEmpty(gateway)) {
                try {
                    //Extract a default gateway from IP address
                    InetAddress netPart = NetworkUtils.getNetworkPart(inetAddr, networkPrefixLength);
                    byte[] addr = netPart.getAddress();
                    addr[addr.length-1] = 1;
                    mGatewayView.setText(InetAddress.getByAddress(addr).getHostAddress());
                } catch (RuntimeException ee) {
                } catch (java.net.UnknownHostException u) {
                }
            } else {
                InetAddress gatewayAddr = getIPv4Address(gateway);
                if (gatewayAddr == null) {
                    return R.string.wifi_ip_settings_invalid_gateway;
                }
                staticIpConfiguration.gateway = gatewayAddr;
            }
    
            String dns = mDns1View.getText().toString();
            InetAddress dnsAddr = null;
    
            if (TextUtils.isEmpty(dns)) {
                //If everything else is valid, provide hint as a default option
                mDns1View.setText(mConfigUi.getContext().getString(R.string.wifi_dns1_hint));
            } else {
                dnsAddr = getIPv4Address(dns);
                if (dnsAddr == null) {
                    return R.string.wifi_ip_settings_invalid_dns;
                }
                staticIpConfiguration.dnsServers.add(dnsAddr);
            }
    
            if (mDns2View.length() > 0) {
                dns = mDns2View.getText().toString();
                dnsAddr = getIPv4Address(dns);
                if (dnsAddr == null) {
                    return R.string.wifi_ip_settings_invalid_dns;
                }
                staticIpConfiguration.dnsServers.add(dnsAddr);
            }
            return 0;
        }
    
        private void showSecurityFields() {
            if (mInXlSetupWizard) {
                // Note: XL SetupWizard won't hide "EAP" settings here.
                if (!((WifiSettingsForSetupWizardXL)mConfigUi.getContext()).initSecurityFields(mView,
                            mAccessPointSecurity)) {
                    return;
                }
            }
            if (mAccessPointSecurity == AccessPoint.SECURITY_NONE) {
                mView.findViewById(R.id.security_fields).setVisibility(View.GONE);
                return;
            }
            mView.findViewById(R.id.security_fields).setVisibility(View.VISIBLE);
    
            if (mPasswordView == null) {
                mPasswordView = (TextView) mView.findViewById(R.id.password);
                mPasswordView.addTextChangedListener(this);
                ((CheckBox) mView.findViewById(R.id.show_password))
                    .setOnCheckedChangeListener(this);
    
                if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
                    mPasswordView.setHint(R.string.wifi_unchanged);
                }
            }
    
            if (mAccessPointSecurity != AccessPoint.SECURITY_EAP) {
                mView.findViewById(R.id.eap).setVisibility(View.GONE);
                return;
            }
            mView.findViewById(R.id.eap).setVisibility(View.VISIBLE);
    
            if (mEapMethodSpinner == null) {
                mEapMethodSpinner = (Spinner) mView.findViewById(R.id.method);
                mEapMethodSpinner.setOnItemSelectedListener(this);
                mPhase2Spinner = (Spinner) mView.findViewById(R.id.phase2);
                mEapCaCertSpinner = (Spinner) mView.findViewById(R.id.ca_cert);
                mEapUserCertSpinner = (Spinner) mView.findViewById(R.id.user_cert);
                mEapIdentityView = (TextView) mView.findViewById(R.id.identity);
                mEapAnonymousView = (TextView) mView.findViewById(R.id.anonymous);
    
                loadCertificates(mEapCaCertSpinner, Credentials.CA_CERTIFICATE);
                loadCertificates(mEapUserCertSpinner, Credentials.USER_PRIVATE_KEY);
    
                // Modifying an existing network
                if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
                    WifiEnterpriseConfig enterpriseConfig = mAccessPoint.getConfig().enterpriseConfig;
                    int eapMethod = enterpriseConfig.getEapMethod();
                    int phase2Method = enterpriseConfig.getPhase2Method();
                    mEapMethodSpinner.setSelection(eapMethod);
                    showEapFieldsByMethod(eapMethod);
                    switch (eapMethod) {
                        case Eap.PEAP:
                            switch (phase2Method) {
                                case Phase2.NONE:
                                    mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_NONE);
                                    break;
                                case Phase2.MSCHAPV2:
                                    mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_MSCHAPV2);
                                    break;
                                case Phase2.GTC:
                                    mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_GTC);
                                    break;
                                default:
                                    Log.e(TAG, "Invalid phase 2 method " + phase2Method);
                                    break;
                            }
                            break;
                        default:
                            mPhase2Spinner.setSelection(phase2Method);
                            break;
                    }
                    setSelection(mEapCaCertSpinner, enterpriseConfig.getCaCertificateAlias());
                    setSelection(mEapUserCertSpinner, enterpriseConfig.getClientCertificateAlias());
                    mEapIdentityView.setText(enterpriseConfig.getIdentity());
                    mEapAnonymousView.setText(enterpriseConfig.getAnonymousIdentity());
                } else {
                    // Choose a default for a new network and show only appropriate
                    // fields
                    mEapMethodSpinner.setSelection(Eap.PEAP);
                    showEapFieldsByMethod(Eap.PEAP);
                }
            } else {
                showEapFieldsByMethod(mEapMethodSpinner.getSelectedItemPosition());
            }
        }
    
        /**
         * EAP-PWD valid fields include
         *   identity
         *   password
         * EAP-PEAP valid fields include
         *   phase2: MSCHAPV2, GTC
         *   ca_cert
         *   identity
         *   anonymous_identity
         *   password
         * EAP-TLS valid fields include
         *   user_cert
         *   ca_cert
         *   identity
         * EAP-TTLS valid fields include
         *   phase2: PAP, MSCHAP, MSCHAPV2, GTC
         *   ca_cert
         *   identity
         *   anonymous_identity
         *   password
         */
        private void showEapFieldsByMethod(int eapMethod) {
            // Common defaults
            mView.findViewById(R.id.l_method).setVisibility(View.VISIBLE);
            mView.findViewById(R.id.l_identity).setVisibility(View.VISIBLE);
    
            // Defaults for most of the EAP methods and over-riden by
            // by certain EAP methods
            mView.findViewById(R.id.l_ca_cert).setVisibility(View.VISIBLE);
            mView.findViewById(R.id.password_layout).setVisibility(View.VISIBLE);
            mView.findViewById(R.id.show_password_layout).setVisibility(View.VISIBLE);
    
            Context context = mConfigUi.getContext();
            switch (eapMethod) {
                case WIFI_EAP_METHOD_PWD:
                    setPhase2Invisible();
                    setCaCertInvisible();
                    setAnonymousIdentInvisible();
                    setUserCertInvisible();
                    break;
                case WIFI_EAP_METHOD_TLS:
                    mView.findViewById(R.id.l_user_cert).setVisibility(View.VISIBLE);
                    setPhase2Invisible();
                    setAnonymousIdentInvisible();
                    setPasswordInvisible();
                    break;
                case WIFI_EAP_METHOD_PEAP:
                    // Reset adapter if needed
                    if (mPhase2Adapter != PHASE2_PEAP_ADAPTER) {
                        mPhase2Adapter = PHASE2_PEAP_ADAPTER;
                        mPhase2Spinner.setAdapter(mPhase2Adapter);
                    }
                    mView.findViewById(R.id.l_phase2).setVisibility(View.VISIBLE);
                    mView.findViewById(R.id.l_anonymous).setVisibility(View.VISIBLE);
                    setUserCertInvisible();
                    break;
                case WIFI_EAP_METHOD_TTLS:
                    // Reset adapter if needed
                    if (mPhase2Adapter != PHASE2_FULL_ADAPTER) {
                        mPhase2Adapter = PHASE2_FULL_ADAPTER;
                        mPhase2Spinner.setAdapter(mPhase2Adapter);
                    }
                    mView.findViewById(R.id.l_phase2).setVisibility(View.VISIBLE);
                    mView.findViewById(R.id.l_anonymous).setVisibility(View.VISIBLE);
                    setUserCertInvisible();
                    break;
            }
        }
    
        private void setPhase2Invisible() {
            mView.findViewById(R.id.l_phase2).setVisibility(View.GONE);
            mPhase2Spinner.setSelection(Phase2.NONE);
        }
    
        private void setCaCertInvisible() {
            mView.findViewById(R.id.l_ca_cert).setVisibility(View.GONE);
            mEapCaCertSpinner.setSelection(unspecifiedCertIndex);
        }
    
        private void setUserCertInvisible() {
            mView.findViewById(R.id.l_user_cert).setVisibility(View.GONE);
            mEapUserCertSpinner.setSelection(unspecifiedCertIndex);
        }
    
        private void setAnonymousIdentInvisible() {
            mView.findViewById(R.id.l_anonymous).setVisibility(View.GONE);
            mEapAnonymousView.setText("");
        }
    
        private void setPasswordInvisible() {
            mPasswordView.setText("");
            mView.findViewById(R.id.password_layout).setVisibility(View.GONE);
            mView.findViewById(R.id.show_password_layout).setVisibility(View.GONE);
        }
    
        private void showIpConfigFields() {
            WifiConfiguration config = null;
    
            mView.findViewById(R.id.ip_fields).setVisibility(View.VISIBLE);
    
            if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
                config = mAccessPoint.getConfig();
            }
    
            if (mIpSettingsSpinner.getSelectedItemPosition() == STATIC_IP) {
                mView.findViewById(R.id.staticip).setVisibility(View.VISIBLE);
                if (mIpAddressView == null) {
                    mIpAddressView = (TextView) mView.findViewById(R.id.ipaddress);
                    mIpAddressView.addTextChangedListener(this);
                    mGatewayView = (TextView) mView.findViewById(R.id.gateway);
                    mGatewayView.addTextChangedListener(this);
                    mNetworkPrefixLengthView = (TextView) mView.findViewById(
                            R.id.network_prefix_length);
                    mNetworkPrefixLengthView.addTextChangedListener(this);
                    mDns1View = (TextView) mView.findViewById(R.id.dns1);
                    mDns1View.addTextChangedListener(this);
                    mDns2View = (TextView) mView.findViewById(R.id.dns2);
                    mDns2View.addTextChangedListener(this);
                }
                if (config != null) {
                    StaticIpConfiguration staticConfig = config.getStaticIpConfiguration();
                    if (staticConfig != null) {
                        if (staticConfig.ipAddress != null) {
                            mIpAddressView.setText(
                                    staticConfig.ipAddress.getAddress().getHostAddress());
                            mNetworkPrefixLengthView.setText(Integer.toString(staticConfig.ipAddress
                                    .getNetworkPrefixLength()));
                        }
    
                        if (staticConfig.gateway != null) {
                            mGatewayView.setText(staticConfig.gateway.getHostAddress());
                        }
    
                        Iterator<InetAddress> dnsIterator = staticConfig.dnsServers.iterator();
                        if (dnsIterator.hasNext()) {
                            mDns1View.setText(dnsIterator.next().getHostAddress());
                        }
                        if (dnsIterator.hasNext()) {
                            mDns2View.setText(dnsIterator.next().getHostAddress());
                        }
                    }
                }
            } else {
                mView.findViewById(R.id.staticip).setVisibility(View.GONE);
            }
        }
    
        private void showProxyFields() {
            WifiConfiguration config = null;
    
            mView.findViewById(R.id.proxy_settings_fields).setVisibility(View.VISIBLE);
    
            if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
                config = mAccessPoint.getConfig();
            }
    
            if (mProxySettingsSpinner.getSelectedItemPosition() == PROXY_STATIC) {
                setVisibility(R.id.proxy_warning_limited_support, View.VISIBLE);
                setVisibility(R.id.proxy_fields, View.VISIBLE);
                setVisibility(R.id.proxy_pac_field, View.GONE);
                if (mProxyHostView == null) {
                    mProxyHostView = (TextView) mView.findViewById(R.id.proxy_hostname);
                    mProxyHostView.addTextChangedListener(this);
                    mProxyPortView = (TextView) mView.findViewById(R.id.proxy_port);
                    mProxyPortView.addTextChangedListener(this);
                    mProxyExclusionListView = (TextView) mView.findViewById(R.id.proxy_exclusionlist);
                    mProxyExclusionListView.addTextChangedListener(this);
                }
                if (config != null) {
                    ProxyInfo proxyProperties = config.getHttpProxy();
                    if (proxyProperties != null) {
                        mProxyHostView.setText(proxyProperties.getHost());
                        mProxyPortView.setText(Integer.toString(proxyProperties.getPort()));
                        mProxyExclusionListView.setText(proxyProperties.getExclusionListAsString());
                    }
                }
            } else if (mProxySettingsSpinner.getSelectedItemPosition() == PROXY_PAC) {
                setVisibility(R.id.proxy_warning_limited_support, View.GONE);
                setVisibility(R.id.proxy_fields, View.GONE);
                setVisibility(R.id.proxy_pac_field, View.VISIBLE);
    
                if (mProxyPacView == null) {
                    mProxyPacView = (TextView) mView.findViewById(R.id.proxy_pac);
                    mProxyPacView.addTextChangedListener(this);
                }
                if (config != null) {
                    ProxyInfo proxyInfo = config.getHttpProxy();
                    if (proxyInfo != null) {
                        mProxyPacView.setText(proxyInfo.getPacFileUrl().toString());
                    }
                }
            } else {
                setVisibility(R.id.proxy_warning_limited_support, View.GONE);
                setVisibility(R.id.proxy_fields, View.GONE);
                setVisibility(R.id.proxy_pac_field, View.GONE);
            }
        }
    
        private void setVisibility(int id, int visibility) {
            final View v = mView.findViewById(id);
            if (v != null) {
                v.setVisibility(visibility);
            }
        }
    
        private void loadCertificates(Spinner spinner, String prefix) {
            final Context context = mConfigUi.getContext();
    
            String[] certs = KeyStore.getInstance().saw(prefix, android.os.Process.WIFI_UID);
            if (certs == null || certs.length == 0) {
                certs = new String[] {unspecifiedCert};
            } else {
                final String[] array = new String[certs.length + 1];
                array[0] = unspecifiedCert;
                System.arraycopy(certs, 0, array, 1, certs.length);
                certs = array;
            }
    
            final ArrayAdapter<String> adapter = new ArrayAdapter<String>(
                    context, android.R.layout.simple_spinner_item, certs);
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            spinner.setAdapter(adapter);
        }
    
        private void setSelection(Spinner spinner, String value) {
            if (value != null) {
                @SuppressWarnings("unchecked")
                ArrayAdapter<String> adapter = (ArrayAdapter<String>) spinner.getAdapter();
                for (int i = adapter.getCount() - 1; i >= 0; --i) {
                    if (value.equals(adapter.getItem(i))) {
                        spinner.setSelection(i);
                        break;
                    }
                }
            }
        }
    
        public boolean isEdit() {
            return mEdit;
        }
    
        @Override
        public void afterTextChanged(Editable s) {
            mTextViewChangedHandler.post(new Runnable() {
                    public void run() {
                        enableSubmitIfAppropriate();
                    }
                });
        }
    
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            // work done in afterTextChanged
        }
    
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            // work done in afterTextChanged
        }
    
        @Override
        public void onCheckedChanged(CompoundButton view, boolean isChecked) {
            if (view.getId() == R.id.show_password) {
                int pos = mPasswordView.getSelectionEnd();
                mPasswordView.setInputType(
                        InputType.TYPE_CLASS_TEXT | (isChecked ?
                                InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD :
                                    InputType.TYPE_TEXT_VARIATION_PASSWORD));
                if (pos >= 0) {
                    ((EditText)mPasswordView).setSelection(pos);
                }
            } else if (view.getId() == R.id.wifi_advanced_togglebox) {
                if (isChecked) {
                    mView.findViewById(R.id.wifi_advanced_fields).setVisibility(View.VISIBLE);
                } else {
                    mView.findViewById(R.id.wifi_advanced_fields).setVisibility(View.GONE);
                }
            }
        }
    
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            if (parent == mSecuritySpinner) {
                mAccessPointSecurity = position;
                showSecurityFields();
            } else if (parent == mEapMethodSpinner) {
                showSecurityFields();
            } else if (parent == mProxySettingsSpinner) {
                showProxyFields();
            } else {
                showIpConfigFields();
            }
            enableSubmitIfAppropriate();
        }
    
        @Override
        public void onNothingSelected(AdapterView<?> parent) {
            //
        }
    
        /**
         * Make the characters of the password visible if show_password is checked.
         */
        private void updatePasswordVisibility(boolean checked) {
            int pos = mPasswordView.getSelectionEnd();
            mPasswordView.setInputType(
                    InputType.TYPE_CLASS_TEXT | (checked ?
                            InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD :
                                InputType.TYPE_TEXT_VARIATION_PASSWORD));
            if (pos >= 0) {
                ((EditText)mPasswordView).setSelection(pos);
            }
        }
    }
    
    

    3. 小结:

    1. 如上, 贴上了原生 Android 5.5 Settings 关于 WIFI 部分源代码的核心部分, 供日后查询方便!
    2. 文章仅供记录, 学习, 以及查询.

    相关文章

      网友评论

        本文标题:Android-WiFi开发之 Android 5.0 代码解析

        本文链接:https://www.haomeiwen.com/subject/hcpdsftx.html