• 在 WifiConfigManager 中通过 createNewInternalWifiConfigurationFromExternal 创建新的 WifiConfiguration 配置项,并且创建合法的 networkId 信息,通过 mNextNetworkId 参数递增的方式对新创建的 Network 赋值 Id;
  • 创建过程发生在 addOrUpdateNetworkInternal 接口中,进行网络的添加,其中传入的 config 为空或者是新的 config 信息,networkId 为 INVALID 的;
  • addOrUpdateNetworkInternal 的调用者很多,从新添加网络的方向来看是 addOrUpdateNetwork 接口,同属于 WifiConfigManager 类,而同样它也有多个调用者;
  • 添加新网络的调用者为 ClientModeImpl 类中的 connect 接口,而它的调用者为 WifiServiceImpl 的 connect 接口:
    /*** see {@link android.net.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.Manifest.permission.NETWORK_SETTINGS,android.Manifest.permission.NETWORK_SETUP_WIZARD,android.Manifest.permission.NETWORK_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.Manifest.permission.NETWORK_SETTINGS,android.Manifest.permission.NETWORK_SETUP_WIZARD,android.Manifest.permission.NETWORK_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(mWifiConfig.networkId, 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 扫描并选择网络进行连接相关推荐

  1. Android Wifi 扫描及自动连接

    Android Wifi 扫描及自动连接 缘起 拆解需求 核心API 权限 核心代码 完整Demo 缘起 最近有个需求,要求App能够自动扫描到某个热点然后自动连接上热点.背景是我们公司属于IoT行业 ...

  2. Android wifi扫描机制(Android O)

    版权声明:本文为博主原创文章,博客地址:https://blog.csdn.net/h784707460/article/details/79658950,未经博主允许不得转载. 一. Android ...

  3. android wifi扫描间隔,[RK3399][Android7.1] 调试笔记 --- WiFi扫描周期规则

    Platform: RK3399 OS: Android 7.1 Kernel: v4.4.83 亮屏情况: 1. 在WiFi Settings界面,无论WiFi是否有连接,固定扫描时间间隔为10s. ...

  4. android WiFi扫描并连接

    wifi扫描并显示 获取列表 获取Wifi列表并不难,网上有一个WifiAdmin的工具类,一找一大堆.但是这个工具类其中还是有很多问题的,并不建议直接使用.在使用过程中还是踩到了其中的一些坑,然后修 ...

  5. Android WiFi 权限、广播、连接、踩坑相关记录

    emmm-最近项目首页重构,UI重新弄,逻辑拆分重新写,变成我来写了-写完了,踩了好几个坑,好几个都忘记了,赶紧记一下防止都忘记了- 1.权限请求- 既然是WiFi连接,当然首先考虑到的是打开WiFi ...

  6. android wifi热点的创建以及连接通信(华为T8951 Google GALAXY Nexus 测试通过)

                   参考网上的很多的资料,初步实现了wifi热点的创建.连接以及聊天通信,以下是网上广为流传的Wifi 三种配置: public WifiConfiguration crea ...

  7. android wifi 扫描频率,Android WIFI扫描时延

    希望大家能够给个评论,支持下新人,感激不尽. 本文第一篇CSDN博客,欢迎大家关注,如有错误,欢迎批评指正. 本人在做WIFI室内定位时发现Android扫描WIFI的时延不小.在此先附上我扫描wif ...

  8. android n wifi scan,Android WiFi扫描

    Wifi扫描 权限方面 必须权限如下: ACCESS_WIFI_STATE(用于扫描结束后读取wifi信息) CHANGE_WIFI_STATE(用于扫描WiFi列表) 除必须权限外,根据系统版本,还 ...

  9. Android WIFI扫描时延

    希望大家能够给个评论,支持下新人,感激不尽. 本文第一篇CSDN博客,欢迎大家关注,如有错误,欢迎批评指正. 本人在做WIFI室内定位时发现Android扫描WIFI的时延不小.在此先附上我扫描wif ...

  10. android wifi 验证失败怎么办,手机连接wifi身份验证失败怎么回事【图】

    原标题:"手机连接wifi身份验证出现问题怎么办?[图]"的相关路由器192.168.1.1登陆页面设置教程资料分享.- 来源:191路由网. 问:手机连接wifi身份验证出现问题 ...

最新文章

  1. 第一次来请大家多多关照---毕业生找工作篇
  2. Android 4.0 Notification
  3. 太难了~面试官让我结合案例讲讲自己对Spring事务传播行为的理解!
  4. rnn参数共享的原因之一
  5. mysql语句:索引,游标,存储过程,视图,分区,分库分表,数据库集群,数据库负载均衡...
  6. Unsupported Hardware Detected
  7. python---(6)函数
  8. 汽车金融平台百金贷宣布良性退出网贷业务
  9. visualboyadvance滤镜_研究VisualBoyAdvance的请进
  10. oracle12兼容ojdbc6,oracle ojdbc6 使用 报错
  11. 打印机扫描显示服务器没有响应,打印机扫描一体机能够打印却不能扫描,提示缺少WIA的驱动程序...
  12. CentOS官网下载对应版本
  13. python怎样计算增长率_Python令人难以置信的增长
  14. 《大数据时代》读后感,维克托
  15. InstallShield软件详解
  16. C++ 模板(泛型)
  17. 关于LCD_ShowString的顽固感叹号!
  18. 从MySQL中读取股票数据——从零到实盘10
  19. PCB过孔的孔径大小对通流的影响
  20. 区块链版权登记_利用区块链版权证书证明著作权

热门文章

  1. [Search Engine] 搜索引擎技术之查询处理
  2. php url地址栏传中文乱码解决方法集合
  3. 7.28-说说对javaweb的感想吧
  4. 简单的三层框架以及使用dbutils进行数据库操作(入门)
  5. Netty4.0学习笔记系列之三:构建简单的http服务
  6. Knockout应用开发指南 第一章:入门
  7. ubuntu gnome vnc
  8. 解决NTLDR is missing,系统无法启动的方法
  9. Asp.Net前台页面调用后台cs变量
  10. CSS中的position 和z-index