失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > Android WiFi 扫描并选择网络进行连接

Android WiFi 扫描并选择网络进行连接

时间:2020-12-25 02:05:31

相关推荐

Android WiFi 扫描并选择网络进行连接

在 WifiConfigManager 中通过createNewInternalWifiConfigurationFromExternal 创建新的 WifiConfiguration 配置项,并且创建合法的 networkId 信息,通过 mNextNetworkId 参数递增的方式对新创建的 Network 赋值 Id;创建过程发生在addOrUpdateNetworkInternal 接口中,进行网络的添加,其中传入的 config 为空或者是新的 config 信息,networkId 为 INVALID 的;addOrUpdateNetworkInternal 的调用者很多,从新添加网络的方向来看是addOrUpdateNetwork 接口,同属于 WifiConfigManager 类,而同样它也有多个调用者;添加新网络的调用者为 ClientModeImpl 类中的 connect 接口,而它的调用者为 WifiServiceImpl 的 connect 接口:

/*** see {@link .wifi.WifiManager#connect(int, WifiManager.ActionListener)}*/@Overridepublic void connect(WifiConfiguration config, int netId, IBinder binder,@Nullable IActionListener callback, int callbackIdentifier) {int uid = Binder.getCallingUid();if (!isPrivileged(Binder.getCallingPid(), uid)) {throw new SecurityException(TAG + ": Permission denied");}mLog.info("connect uid=%").c(uid).flush();mClientModeImpl.connect(config, netId, binder, callback, callbackIdentifier, uid);if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_MANUAL_CONNECT, netId);}}

其调用为通过 binder 服务在 WifiManager中发生,其中通过 connect 接口进行连接过程访问,而 connect 接口通过 connectInternal 接口调用了 mService.connect,即访问到 WifiServiceImpl 中对应的方法:

private void connectInternal(@Nullable WifiConfiguration config, int networkId,@Nullable ActionListener listener) {ActionListenerProxy listenerProxy = null;Binder binder = null;if (listener != null) {listenerProxy = new ActionListenerProxy("connect", mLooper, listener);binder = new Binder();}try {mService.connect(config, networkId, binder, listenerProxy,listener == null ? 0 : listener.hashCode());} catch (RemoteException e) {if (listenerProxy != null) listenerProxy.onFailure(ERROR);} catch (SecurityException e) {if (listenerProxy != null) listenerProxy.onFailure(NOT_AUTHORIZED);}}/*** Connect to a network with the given configuration. The network also* gets added to the list of configured networks for the foreground user.** For a new network, this function is used instead of a* sequence of addNetwork(), enableNetwork(), and reconnect()** @param config the set of variables that describe the configuration,* contained in a {@link WifiConfiguration} object.* @param listener for callbacks on success or failure. Can be null.* @throws IllegalStateException if the WifiManager instance needs to be* initialized again** @hide*/@SystemApi@RequiresPermission(anyOf = {android.WORK_SETTINGS,android.WORK_SETUP_WIZARD,android.WORK_STACK})public void connect(@NonNull WifiConfiguration config, @Nullable ActionListener listener) {if (config == null) throw new IllegalArgumentException("config cannot be null");connectInternal(config, WifiConfiguration.INVALID_NETWORK_ID, listener);}/*** Connect to a network with the given networkId.** This function is used instead of a enableNetwork() and reconnect()** <li> This API will cause reconnect if the credentials of the current active* connection has been changed.</li>* <li> This API will cause reconnect if the current active connection is marked metered.</li>** @param networkId the ID of the network as returned by {@link #addNetwork} or {@link* getConfiguredNetworks}.* @param listener for callbacks on success or failure. Can be null.* @throws IllegalStateException if the WifiManager instance needs to be* initialized again* @hide*/@SystemApi@RequiresPermission(anyOf = {android.WORK_SETTINGS,android.WORK_SETUP_WIZARD,android.WORK_STACK})public void connect(int networkId, @Nullable ActionListener listener) {if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");connectInternal(null, networkId, listener);}

到用户界面层面的调用发生在 StandardWifiEntry 类中,其中调用了connect 接口,通过 mWifiManager 的 connect 接口调用进行网络连接:

@Overridepublic void connect(@Nullable ConnectCallback callback) {mConnectCallback = callback;// We should flag this network to auto-open captive portal since this method represents// the user manually connecting to a network (i.e. not auto-join).mShouldAutoOpenCaptivePortal = true;if (isSaved() || isSuggestion()) {// Saved/suggested networkmWifiManager.connect(workId, new ConnectActionListener());} else {// Unsaved networkif (mSecurity == SECURITY_NONE|| mSecurity == SECURITY_OWE) {// Open networkfinal WifiConfiguration connectConfig = new WifiConfiguration();connectConfig.SSID = "\"" + mSsid + "\"";if (mSecurity == SECURITY_OWE) {// Use OWE if possibleconnectConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);connectConfig.requirePmf = true;} else {connectConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);}mWifiManager.connect(connectConfig, new ConnectActionListener());} else {// Secure networkif (callback != null) {mCallbackHandler.post(() ->callback.onConnectResult(ConnectCallback.CONNECT_STATUS_FAILURE_NO_CONFIG));}}}}

上述对 Unsaved Network 的处理过程中通过 ssid 和 password 信息构建网络配置,以 INVALID 类型的 networkId 信息设定传下来进行连接;这里的 connect 调用发生在 WifiSettings2 中的connect 中,进而是在 onSubmit 接口中被调用,或者在onPreferenceTreeClick 中被调用,从而进行编辑获取信息下发进行配置

@Overridepublic void onSubmit(WifiDialog2 dialog) {final int dialogMode = dialog.getMode();final WifiConfiguration config = dialog.getController().getConfig();final WifiEntry wifiEntry = dialog.getWifiEntry();if (dialogMode == WifiConfigUiBase2.MODE_MODIFY) {if (config == null) {Toast.makeText(getContext(), R.string.wifi_failed_save_message,Toast.LENGTH_SHORT).show();} else {mWifiManager.save(config, mSaveListener);}} else if (dialogMode == WifiConfigUiBase2.MODE_CONNECT|| (dialogMode == WifiConfigUiBase2.MODE_VIEW && wifiEntry.canConnect())) {if (config == null) {connect(wifiEntry, false /* editIfNoConfig */,false /* fullScreenEdit*/);} else {mWifiManager.connect(config, new WifiConnectActionListener());}}}@VisibleForTestingvoid connect(WifiEntry wifiEntry, boolean editIfNoConfig, boolean fullScreenEdit) {mMetricsFeatureProvider.action(getActivity(), SettingsEnums.ACTION_WIFI_CONNECT,wifiEntry.isSaved());// If it's an unsaved secure WifiEntry, it will callback// ConnectCallback#onConnectResult with ConnectCallback#CONNECT_STATUS_FAILURE_NO_CONFIGwifiEntry.connect(new WifiEntryConnectCallback(wifiEntry, editIfNoConfig,fullScreenEdit));}

扫描结果接收到 UI 层

在 BaseWifiTracker 类中创建了 BroadcastReceiver 类对象 mBroadcastReceiver 来接收广播信息,其中的 onReceive 接口处理及收到的广播,其中对WifiManager.WIFI_STATE_CHANGED_ACTION 广播进行处理;其中会进行notifyOnWifiStateChanged 和handleWifiStateChangedAction 操作;在继承类 WifiPickerTracker 中进行handleWifiStateChangedAction 的重载,进行了updateWifiEntries 调用更新了 WifiEntry 信息;在上述的更新过程中都会推后调用onWifiEntriesChanged 接口,而在 WifiSettings2 类中它被重载:

@Overridepublic void onWifiEntriesChanged() {updateWifiEntryPreferencesDelayed();changeNextButtonState(mWifiPickerTracker.getConnectedWifiEntry() != null);// Edit the Wi-Fi network of specified SSID.if (mOpenSsid != null) {Optional<WifiEntry> matchedWifiEntry = mWifiPickerTracker.getWifiEntries().stream().filter(wifiEntry -> TextUtils.equals(mOpenSsid, wifiEntry.getSsid())).filter(wifiEntry -> wifiEntry.getSecurity() != WifiEntry.SECURITY_NONE&& wifiEntry.getSecurity() != WifiEntry.SECURITY_OWE).filter(wifiEntry -> !wifiEntry.isSaved()|| isDisabledByWrongPassword(wifiEntry)).findFirst();if (matchedWifiEntry.isPresent()) {mOpenSsid = null;launchConfigNewNetworkFragment(matchedWifiEntry.get());}}}

上述调用过程让更新到的 WifiEntry 信息显示在用户界面。下面分析BroadcastReceiver 接收的消息源。

在 ScanRequestProxy 类的实现中,调用了sendScanResultBroadcast 直接将对应的WifiManager.SCAN_RESULTS_AVAILABLE_ACTION 消息进行了广播,从而给用户界面层接收到;

sendScanResultBroadcast 在GlobalScanListener 中的 onResults 接口中被调用,而其类对象在 ScanRequestProxy 类的retrieveWifiScannerIfNecessary 接口中获取到 WifiScanner 对象时调用它进行创建,并且注册到了 WifiScanner 中;

从而在 WifiScanner 中通过 AsyncChannel 发送了CMD_REGISTER_SCAN_LISTENER 消息到另一端 WifiScanningServiceImpl 中对相应的 Scan 结果进行监听,收取结果之后进行 ScanListener 的回调,实际发生在 ServiceHandler 内部类中进行 handleMessage 中的处理过程处理 CMD_SCAN_RESULT 过程中,对所有的 Listener 进行遍历并将相应的结果进行回调告知处理。

如果觉得《Android WiFi 扫描并选择网络进行连接》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。