Android系统WIFI设置源码解析

Android系统设置界面中的WIFI页面是在packages\apps\Settings\src\com\android\settings\Settings$WifiSettingsActivity,.
下面我们对WIFISettingsActivity进行分析.

以下是onCreate方法

@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);

    // Should happen before any call to getIntent()
    //从AndroidManifest.xml文件中读取metaData数据,取出需要显示的碎片完整类名
    getMetaData();

    final Intent intent = getIntent();
    if (intent.hasExtra(EXTRA_UI_OPTIONS)) {
        getWindow().setUiOptions(intent.getIntExtra(EXTRA_UI_OPTIONS, 0));
    }

    mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE,
            Context.MODE_PRIVATE);

    // Getting Intent properties can only be done after the super.onCreate(...)
    final String initialFragmentName = intent.getStringExtra(EXTRA_SHOW_FRAGMENT);
    //表示即将显示的界面是否是快捷键
    mIsShortcut = isShortCutIntent(intent) || isLikeShortCutIntent(intent) ||
            intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, false);

    final ComponentName cn = intent.getComponent();
    final String className = cn.getClassName();
    //表示即将显示的界面是否是设置主页面
    mIsShowingDashboard = className.equals(Settings.class.getName());

    // This is a "Sub Settings" when:
    // - this is a real SubSettings
    // - or :settings:show_fragment_as_subsetting is passed to the Intent
    final boolean isSubSettings = className.equals(SubSettings.class.getName()) ||
            intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SUBSETTING, false);

    // If this is a sub settings, then apply the SubSettings Theme for the ActionBar content insets
    if (isSubSettings) {
        // Check also that we are not a Theme Dialog as we don't want to override them
        final int themeResId = getThemeResId();
        if (themeResId != R.style.Theme_DialogWhenLarge &&
                themeResId != R.style.Theme_SubSettingsDialogWhenLarge) {
            setTheme(R.style.Theme_SubSettings);
        }
    }
    //如果是首页就将内容布局设置成settings_main_dashboard,否则就设置成settings_main_prefs
    setContentView(mIsShowingDashboard ?
            R.layout.settings_main_dashboard : R.layout.settings_main_prefs);
    //用于展现内容的布局
    mContent = (ViewGroup) findViewById(R.id.main_content);

    getFragmentManager().addOnBackStackChangedListener(this);

    if (mIsShowingDashboard) {
        Index.getInstance(getApplicationContext()).update();
    }

    if (savedState != null) {
        // We are restarting from a previous saved state; used that to initialize, instead
        // of starting fresh.
        mSearchMenuItemExpanded = savedState.getBoolean(SAVE_KEY_SEARCH_MENU_EXPANDED);
        mSearchQuery = savedState.getString(SAVE_KEY_SEARCH_QUERY);

        setTitleFromIntent(intent);

        ArrayList<DashboardCategory> categories =
                savedState.getParcelableArrayList(SAVE_KEY_CATEGORIES);
        if (categories != null) {
            mCategories.clear();
            mCategories.addAll(categories);
            setTitleFromBackStack();
        }

        mDisplayHomeAsUpEnabled = savedState.getBoolean(SAVE_KEY_SHOW_HOME_AS_UP);
        mDisplaySearch = savedState.getBoolean(SAVE_KEY_SHOW_SEARCH);
        mHomeActivitiesCount = savedState.getInt(SAVE_KEY_HOME_ACTIVITIES_COUNT,
                1 /* one home activity by default */);
    } else {
        if (!mIsShowingDashboard) {
            // Search is shown we are launched thru a Settings "shortcut". UP will be shown
            // only if it is a sub settings
            if (mIsShortcut) {
                mDisplayHomeAsUpEnabled = isSubSettings;
                mDisplaySearch = false;
            } else if (isSubSettings) {
                mDisplayHomeAsUpEnabled = true;
                mDisplaySearch = true;
            } else {
                mDisplayHomeAsUpEnabled = false;
                mDisplaySearch = false;
            }
            setTitleFromIntent(intent);

            Bundle initialArguments = intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
			//对mContent对应的部分用碎片来替换
            switchToFragment(initialFragmentName, initialArguments, true, false,
                    mInitialTitleResId, mInitialTitle, false);
        } else {
            // No UP affordance if we are displaying the main Dashboard
            mDisplayHomeAsUpEnabled = false;
            // Show Search affordance
            mDisplaySearch = true;
            mInitialTitleResId = R.string.dashboard_title;
            switchToFragment(DashboardSummary.class.getName(), null, false, false,
                    mInitialTitleResId, mInitialTitle, false);
        }
    }

    mActionBar = getActionBar();
    if (mActionBar != null) {
        mActionBar.setDisplayHomeAsUpEnabled(mDisplayHomeAsUpEnabled);
        mActionBar.setHomeButtonEnabled(mDisplayHomeAsUpEnabled);
    }
    mSwitchBar = (SwitchBar) findViewById(R.id.switch_bar);

    // see if we should show Back/Next buttons
    if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false)) {

        View buttonBar = findViewById(R.id.button_bar);
        if (buttonBar != null) {
            buttonBar.setVisibility(View.VISIBLE);

            Button backButton = (Button)findViewById(R.id.back_button);
            backButton.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    setResult(RESULT_CANCELED, getResultIntentData());
                    finish();
                }
            });
            Button skipButton = (Button)findViewById(R.id.skip_button);
            skipButton.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    setResult(RESULT_OK, getResultIntentData());
                    finish();
                }
            });
            mNextButton = (Button)findViewById(R.id.next_button);
            mNextButton.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    setResult(RESULT_OK, getResultIntentData());
                    finish();
                }
            });

            // set our various button parameters
            if (intent.hasExtra(EXTRA_PREFS_SET_NEXT_TEXT)) {
                String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_NEXT_TEXT);
                if (TextUtils.isEmpty(buttonText)) {
                    mNextButton.setVisibility(View.GONE);
                }
                else {
                    mNextButton.setText(buttonText);
                }
            }
            if (intent.hasExtra(EXTRA_PREFS_SET_BACK_TEXT)) {
                String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_BACK_TEXT);
                if (TextUtils.isEmpty(buttonText)) {
                    backButton.setVisibility(View.GONE);
                }
                else {
                    backButton.setText(buttonText);
                }
            }
            if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_SKIP, false)) {
                skipButton.setVisibility(View.VISIBLE);
            }
        }
    }
    //获取Launcher APP的数量
    mHomeActivitiesCount = getHomeActivitiesCount();
}

从上面的分析我们可以得知,WIFI设置页面实际的操作是在WifiSettings.java,下面我们进入WifiSettings.

我们先介绍下它的内部类Scanner,

private static class Scanner extends Handler {
private int mRetry = 0;
private WifiSettings mWifiSettings = null;

    Scanner(WifiSettings wifiSettings) {
        mWifiSettings = wifiSettings;
    }

    //开启WIFI扫描
    void resume() {
        if (!hasMessages(0)) {
            sendEmptyMessage(0);
        }
    }
    //强制开始进行WIFI扫描
    void forceScan() {
        removeMessages(0);
        sendEmptyMessage(0);
    }
    //暂停WIFI扫描,并将WIFI扫描重试次数重置
    void pause() {
        mRetry = 0;
        removeMessages(0);
    }

    @Override
    public void handleMessage(Message message) {
        //如果WIFI扫描开启成功,就将WIFI扫描重试次数重置
        if (mWifiSettings.mWifiManager.startScan()) {
            mRetry = 0;
			//如果WIFI扫描连续失败次数超过三次,就提示用户WIFI扫描失败,并停止继续尝试开启WIFI扫描
        } 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;
        }
		//WIFI扫描每隔10秒重试一次
        sendEmptyMessageDelayed(0, WIFI_RESCAN_INTERVAL_MS);
    }
}

由上面的分析可以得知,他是负责WIFI扫描的,扫描连续失败超过三次就停止扫描并且通知客户.
从SettingsActivity,java我们可知设置页面里的所有的碎片都是通过无参构造方法来实例化的,所以我们从它的无参构造方法入手,
以下是其构造方法

//对用于监听网络包括网络改变,WIFI状态改变,网络配置改变等等8个事件监听的广播接受者实例化,
//和WIFI扫描器的实例化
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);
}

接着我们进入onActivityCreated方法

@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);

    mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
    //WIFI连接失败监听回调
    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();
                                   }
                               }
                           };
	//WIFI密码保存失败监听回调

    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();
                                   }
                               }
                           };
	//如果是从异常中恢复并且是在编辑WIFI密码的场景下,就获取发生异常时候保存的状态

    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());
            }
        }
    }
    //设置WIFI设置显示布局
    addPreferencesFromResource(R.xml.wifi_settings);

    //WIF列表为空是否显示的View
    mEmptyView = initEmptyView();
	//注册上下文菜单
    registerForContextMenu(getListView());
	//触发上下文菜单重新创建
    setHasOptionsMenu(true);
     //如果启动WIFI界面时候携带了WIFI SSID
    if (intent.hasExtra(EXTRA_START_CONNECT_SSID)) {
        String ssid = intent.getStringExtra(EXTRA_START_CONNECT_SSID);
		//更新WIFI访问节点状态
        updateAccessPoints();
        PreferenceScreen preferenceScreen = getPreferenceScreen();
		//遍历所有的WIFI访问节点,找到等于启动wifi设置页面需要连接的wifi SSID,如果WIFI不是开放的,
		//就显示输入密码的dialog.
        for (int i = 0; i < preferenceScreen.getPreferenceCount(); i++) {
            Preference preference = preferenceScreen.getPreference(i);
            if (preference instanceof AccessPoint) {
                AccessPoint accessPoint = (AccessPoint) preference;
                if (ssid.equals(accessPoint.ssid) && accessPoint.networkId == -1
                        && accessPoint.security != AccessPoint.SECURITY_NONE) {
                    onPreferenceTreeClick(preferenceScreen, preference);
                    break;
                }
            }
        }
    }
}

下面我们介绍下WifiEnabler,这个类的主要作用就是根据WIFI开启与关闭的不同状态,来变更WIFI开关的不同状态.

//传递mSwitchBar对象,实例化mWifiManager等对象,并且及时更新mSwitchBar的显示状态,且根据不同的状态来决定是否为其添加切换监听事件
public WifiEnabler(Context context, SwitchBar switchBar) {
mContext = context;
mSwitchBar = switchBar;

    mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);

    mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
    // The order matters! We really should not depend on this. :(
    mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
    mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
    
    setupSwitchBar();
}

//更新SwitchBar状态,并且为其添加切换事件,显示出SwitchBar
public void setupSwitchBar() {
    final int state = mWifiManager.getWifiState();
    handleWifiStateChanged(state);
    if (!mListeningToOnSwitchChange) {
        mSwitchBar.addOnSwitchChangeListener(this);
        mListeningToOnSwitchChange = true;
    }
    mSwitchBar.show();
}

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
		//根据WIFI开关状态来变更SwitchBar的状态
        if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
            handleWifiStateChanged(intent.getIntExtra(
                    WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN));
        } else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
            if (!mConnected.get()) {
				//空实现
                handleStateChanged(WifiInfo.getDetailedStateOf((SupplicantState)
                        intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE)));
            }
        } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
            NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
                    WifiManager.EXTRA_NETWORK_INFO);
			//保存网络连接状态
            mConnected.set(info.isConnected());
			//空实现
            handleStateChanged(info.getDetailedState());
        }
    }
};

//注册WIFI和网络状态监听广播,并为SwitchBar添加切换监听事件
  public void resume(Context context) {
    mContext = context;
    // Wi-Fi state is sticky, so just let the receiver update UI
    mContext.registerReceiver(mReceiver, mIntentFilter);
    if (!mListeningToOnSwitchChange) {
        mSwitchBar.addOnSwitchChangeListener(this);
        mListeningToOnSwitchChange = true;
    }
}

//解除广播注册,并且移除SwitchBar监听事件
public void pause() {
    mContext.unregisterReceiver(mReceiver);
    if (mListeningToOnSwitchChange) {
        mSwitchBar.removeOnSwitchChangeListener(this);
        mListeningToOnSwitchChange = false;
    }
}

private void handleWifiStateChanged(int state) {
    switch (state) {
		//WIFI正在开启就将mSwitchBar变为不可用状态
        case WifiManager.WIFI_STATE_ENABLING:
            mSwitchBar.setEnabled(false);
            break;
			//WIFI开启成功,就将mSwitchBar设置为选中,并且变为可用状态,更新数据库
        case WifiManager.WIFI_STATE_ENABLED:
            setSwitchBarChecked(true);
            mSwitchBar.setEnabled(true);
            updateSearchIndex(true);
            break;
			//WIFI关闭中,将mSwitchBar置位不可用状态
        case WifiManager.WIFI_STATE_DISABLING:
            mSwitchBar.setEnabled(false);
            break;
			//WIFI关闭成功,将mSwitchBar设置成关闭状态,变为可用状态,且更新数据库
        case WifiManager.WIFI_STATE_DISABLED:
            setSwitchBarChecked(false);
            mSwitchBar.setEnabled(true);
            updateSearchIndex(false);
            break;
        default:
            setSwitchBarChecked(false);
            mSwitchBar.setEnabled(true);
            updateSearchIndex(false);
    }
}

     @Override
    public void onSwitchChanged(Switch switchView, boolean isChecked) {
    //Do nothing if called as a result of a state machine event
    if (mStateMachineEvent) {
        return;
    }
    // Show toast message if Wi-Fi is not allowed in airplane mode
    //如果在飞行模式下mSwitchBar被开启,就立马将其关闭掉
    if (isChecked && !WirelessSettings.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI)) {
        Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
        // Reset switch to off. No infinite check/listenenr loop.
        mSwitchBar.setChecked(false);
        return;
    }

    // Disable tethering if enabling Wifi
    int wifiApState = mWifiManager.getWifiApState();
	//如果WIFI正在开启状态,就将其置位不可用状态
    if (isChecked && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
            (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
        mWifiManager.setWifiApEnabled(null, false);
    }
      //如果WIFI开启或者关闭失败,将mSwitchBar置位可用状态,并且提示WFI错误
    if (!mWifiManager.setWifiEnabled(isChecked)) {
        // Error
        mSwitchBar.setEnabled(true);
        Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();
    }
}

接着我们接着分析WifiSettings.java
     //移除WIFI开关的切换监听事件并且将其隐藏起来
   @Override
public void onDestroyView() {
    super.onDestroyView();

    if (mWifiEnabler != null) {
        mWifiEnabler.teardownSwitchBar();
    }
}
//创建mWifiEnabler 对象
@Override
public void onStart() {
    super.onStart();

    // On/off switch is hidden for Setup Wizard (returns null)
    mWifiEnabler = createWifiEnabler();
}


//WIFI状态开关状态更新,注册广播接受者并且及时更新WIFI列表
@Override
public void onResume() {
    final Activity activity = getActivity();
    super.onResume();
    if (mWifiEnabler != null) {
        mWifiEnabler.resume(activity);
    }

    activity.registerReceiver(mReceiver, mFilter);
    updateAccessPoints();
}

//移除WIFI开关状态的监听,并且解除广播接受者的注册
@Override
public void onPause() {
    super.onPause();
    if (mWifiEnabler != null) {
        mWifiEnabler.pause();
    }

    getActivity().unregisterReceiver(mReceiver);
    mScanner.pause();
}
 以下是忘记密码和提交按钮点击后执行的操作
//开始连接WIFI
/* package */ void submit(WifiConfigController configController) {

    final WifiConfiguration config = configController.getConfig();

	 //如果WIFI配置为空但是当前选择WIFI访问节点不为空且为合法的就连接
    if (config == null) {
        if (mSelectedAccessPoint != null
                && mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
            connect(mSelectedAccessPoint.networkId);
        }
	//如果WIFI配置不为空且是合法的,并且当前选择的WIFI访问节点不为空就保存配置
    } else if (config.networkId != INVALID_NETWORK_ID) {
        if (mSelectedAccessPoint != null) {
            mWifiManager.save(config, mSaveListener);
        }
    } else {
    //如果当前WIFI配置处于编辑模式就保存其配置,否则直接连接
        if (configController.isEdit()) {
            mWifiManager.save(config, mSaveListener);
        } else {
            connect(config);
        }
    }

	 //如果WIFI是开启的状态就恢复WIFI扫描
    if (mWifiManager.isWifiEnabled()) {
        mScanner.resume();
    }
	//更新WIFI列表UI
    updateAccessPoints();
}
    //忘记网络
/* package */ void forget() {
    if (mSelectedAccessPoint.networkId == INVALID_NETWORK_ID) {
		//如果当前选择的WIFI访问节点处于非断开状态就移除掉当前WIFI
        if (mSelectedAccessPoint.getNetworkInfo().getState() != State.DISCONNECTED) {
            // Network is active but has no network ID - must be ephemeral.
            mWifiManager.disableEphemeralNetwork(
                    AccessPoint.convertToQuotedString(mSelectedAccessPoint.ssid));
        } else {
            // Should not happen, but a monkey seems to trigger it
            Log.e(TAG, "Failed to forget invalid network " + mSelectedAccessPoint.getConfig());
            return;
        }
    } 
     //如果当前选择的WIFI为合法的,就忘记掉当前的WIFI节点
	else {
        mWifiManager.forget(mSelectedAccessPoint.networkId, mForgetListener);
    }
      //如果WIFI处于开启状态,开启WIFI扫描

    if (mWifiManager.isWifiEnabled()) {
        mScanner.resume();
    }
	//更新WIFI列表状态
    updateAccessPoints();

    // We need to rename/replace "Next" button in wifi setup context.
    //禁用到WIFI连接下一步按钮
    changeNextButtonState(false);
}

到此WIFI设置页面的大致分析就告一段落了。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值