33 · 连接全流程:点击 → 密码框 → connect → 回调 → 文案
核心文件:
controller/MiCarBaseWifiEntryController.kt(点击分发)、view/WifiPasswordDialog.kt(密码框)、MiCarWifiUtils.kt(App 侧连接)、wifitrackerlib/StandardWifiEntry.java(库侧连接) 代码基线:fuben_micarsettings @ dev,f3 flavor 关联:30-页面导航(详情页入口)、21-架构篇(WifiEntry 状态机)
0. 总图:三种连接入口殊途同归于 WifiManager
flowchart TD CLICK["列表条目点击<br/>MiCarBaseWifiEntryController:205-236"] --> B1{"已连接?"} B1 -->|是且门户网| SIGN["signIn(门户登录)"] B1 -->|否| B2{"shouldEditBeforeConnect?<br/>密码错被禁用"} B2 -->|是| PWD["直接弹密码框(带'密码错误'红字)<br/>MANNPROB-3405 修复 :218-223"] B2 -->|否| C1["wifiEntry.connect(...)<br/>:224-227"] C1 --> D1{"StandardWifiEntry.connect:508<br/>四分支"} D1 -->|"①saved/suggestion"| M1["WifiManager.connect(networkId):534<br/>静默直连"] D1 -->|"②OWE"| M2["connect(oweConfig);过渡网补 save(open)"] D1 -->|"③OPEN"| M3["connect(openConfig)"] D1 -->|"④未保存加密"| CB["onConnectResult(NO_CONFIG):605-610"] CB --> PWD2["Controller 收到 NO_CONFIG<br/>→ showWifiPasswordDialog:324-329"] PWD --> DLG PWD2 --> DLG["WifiPasswordDialog.show:49"] DLG -->|"输入密码+确认"| MC["MiCarWifiUtils.connect:51<br/>组 WifiConfiguration"] MC --> M4["WifiManager.connect(config)"] DET["详情页'修改密码'按钮"] --> DLG
小白关键认知:未保存加密网的”点击”并不直接连,而是先让库试连 → 库回 NO_CONFIG → App 才弹密码框;密码框路径绕开 WifiEntry.connect,App 自己组 WifiConfiguration 直连框架。
1. 条目点击三分支(MiCarBaseWifiEntryController.kt:205-236)
wifiEntryPreference.onPreferenceClickListener = { _ ->
if (isQuickDoubleClick(...)) return@OnPreferenceClickListener true // :209 防双击(与开关共用时间戳)
if (wifiEntry.isConnected()) {
if (wifiEntry.canSignIn()) { wifiEntry.signIn(null); ... } // :213 已连接门户网→登录
} else if (wifiEntry.shouldEditBeforeConnect()) {
MiCarWifiUtils.tryConnectWifiEntry = wifiEntry
showWifiPasswordDialog(wifiEntry, true) // :218-223 直弹+错误提示(3405)
} else {
MiCarWifiUtils.tryConnectWifiEntry = wifiEntry
wifiEntry.connect(WifiEntryConnectCallback(wifiEntry, true)) // :224-227
}
true
}shouldEditBeforeConnect(StandardWifiEntry.java:866-886):config 存在且(NetworkSelectionStatus 非 ENABLED 或从未连上)且 DISABLED_AUTHENTICATION_FAILURE/DISABLED_BY_WRONG_PASSWORD/DISABLED_AUTHENTICATION_NO_CREDENTIALS 计数>0 → true。- 语音/外部 intent 指定 SSID 自动
performClick()(:231-235,extrakey_chosen_wifientry_key)。
2. WifiPasswordDialog:object 弹窗(object,非 DialogFragment)
- 构造:
show(context, wifiEntry, isShowPasswordWrong, callBack, isRequestFullScreen, showNegativeButton=false)(:49-56);WifiEntry 对象直接传参。 - 企业网身份框:仅
SECURITY_EAP / EAP_SUITE_B / EAP_WPA3_ENTERPRISE显示(:190-196),回填wifiConfiguration?.enterpriseConfig?.identity(:69)。 - 校验(:160-184):确认键初始 disabled,TextWatcher 实时:
密码长度 8~63(WIFI_PWD_LENGTH_RANGE,MiCarWifiUtils.kt:25)+ 企业网身份非空 → 使能。 - 确认:
setPositiveButton(R.string.connect)(:118-125)→callBack.onConnect(wifiEntry, password, identity)→MiCarWifiUtils.connect。 - 没有 loading/禁用转圈:确认即 dismiss,连接过程反馈完全靠条目 CONNECTING 态。
- “密码错误”红字
password_wrong_message(layout:62-71,ModalDanger 色)由isShowPasswordWrong控制显隐(:109-112)。
3. MiCarWifiUtils.connect:App 侧组包直连(:51-69)
fun connect(wifiEntry: WifiEntry, password: String, identity: String) {
val config = getWifiConfig(wifiEntry, password, identity) ?: return // 不支持类型直接放弃
mWifiManager?.connect(config, object : ActionListener {
override fun onSuccess() { /* 只打日志,无 UI */ }
override fun onFailure(reason: Int) { /* 只打日志,无 UI */ }
})
}getWifiConfig(:71-155)建传统 WifiConfiguration(不是 WifiNetworkSuggestion builder):已保存则保留 networkId/hiddenSSID(:76-77——“修改密码重连”的关键);按 security 设 setSecurityParams(PSK 密码加引号/64 位 hex 直传;EAP=PEAP+NONE;EAP_WPA3=PEAP+MSCHAPV2;WAPI 等未知类型返回 null 防崩,N801PROB-135004/129248,:147-152)。
4. 连接后:框架 → tracker → entry 的回调链(状态如何翻到 UI)
sequenceDiagram participant A as App participant F as WifiService/框架 participant T as WifiPickerTracker participant E as WifiEntry participant UI as 列表 A->>F: WifiManager.connect(...) F-->>T: ① NETWORK_STATE_CHANGED 广播 T->>E: onPrimaryWifiInfoChanged:1152(匹配networkId) E->>E: mNetworkInfo=..., DetailedState=CONNECTING/AUTHENTICATING/... Note over E,UI: getConnectedState()=CONNECTING(:333-346)<br/>条目高亮+"正在连接…" F-->>T: ② NetworkCallback.onCapabilitiesChanged(L3通) T->>E: onNetworkCapabilitiesChanged:1173 E->>E: updateWifiInfo:1209 → CONNECTED<br/>mCalledConnect→post onConnectResult(SUCCESS):1228-1238 F-->>T: ③ CONFIGURED_NETWORKS_CHANGED(新密码才有) T->>E: updateConfig:1054 填 mMatchingWifiConfigs Note over E: isSaved()==true,详情按钮/已保存分组生效 T->>UI: updateWifiEntries:610 → notifyOnWifiEntriesChanged UI->>UI: 条目从"可用组"消失→"已保存组"置顶第一行 F-->>T: ④ SCAN_RESULTS(下一轮) T->>E: updateScanResultInfo:963(信号格数刷新)
代码调用链(已保存网点击,完整):
MiCarBaseWifiEntryController#initWifiEntryPreference:206 点击
→ WifiEntry#connect:227 → StandardWifiEntry#connect:508(①分支)
→ WifiManager#connect(networkId):534
→ [NETWORK_STATE_CHANGED 广播] BaseWifiTracker$onReceive:179
→ WifiPickerTracker#handleNetworkStateChangedAction:397-434
conditionallyCreateConnectedWifiEntry:423 + entry.onPrimaryWifiInfoChanged:431
→ WifiEntry#onPrimaryWifiInfoChanged:1152-1166(CONNECTING)
→ [L3通] NetworkCallback#onCapabilitiesChanged:257-272
→ handleNetworkCapabilitiesChanged:465-469 → updateNetworkCapabilities:1387-1405
→ WifiEntry#onNetworkCapabilitiesChanged:1173-1207 → updateWifiInfo:1209-1248
CONNECTED + onConnectResult(SUCCESS):1228-1238
→ WifiPickerTracker#updateWifiEntries:610-791 → notifyOnWifiEntriesChanged:1554
→ MiWifiTrackerUtils:51 → Controller refreshUi → 条目挪入已连接组置顶条目自身的即时刷新:MiCarWifiEntryPreference.onUpdated():187-192(icon/title/summary);连接中文案 = Utils.getConnectingDescription:370-383 按 DetailedState 查 12 态表(arrays.xml:24-36:“正在扫描…/正在连接…/正在验证身份…/正在获取 IP 地址…/已暂停/正在断开连接…/已断开连接/失败/已屏蔽/连接状况不佳,暂时停用”)。
5. 连接失败的 4 层反馈(重点:错误密码场景)
| 层 | 机制 | 位置 | 及时性 |
|---|---|---|---|
| ① inline 小字 | 条目 summary 按 disable reason 映射 | Utils.getWifiConfigurationFailureMessage:466-545(表见下) | 被动、延迟(要等 config 广播回填) |
| ② 失败广播→重弹密码框 | 框架发 micar.intent.action.WIFI_CONNECTION_FAILURE | WifiSettingsActivity#mConnectFailureReceiver:42-56 | 主动 |
| ③ 再点一次 | shouldEditBeforeConnect 直弹 | MiCarBaseWifiEntryController:218-223 | 用户触发 |
| ④ FAILURE_UNKNOWN | 只打一行 log,无任何 UI | :331-333 | — |
①的映射表(zh-rCN strings.xml:24-37):
| NetworkSelectionStatus | 文案 |
|---|---|
| DISABLED_AUTHENTICATION_FAILURE / NO_CREDENTIALS / NO_SUBSCRIPTION | ”身份验证出现问题” |
| DISABLED_BY_WRONG_PASSWORD | ”请检查密码是否正确,然后重试” |
| DISABLED_CONSECUTIVE_FAILURES(从未连上) | “身份验证出现问题” |
| DISABLED_CONSECUTIVE_FAILURES(连上过) | “连接失败” |
| DISABLED_DHCP_FAILURE | ”IP 配置失败” |
| DISABLED_ASSOCIATION_REJECTION | ”已停用” |
| AP 满载/拒接 | ”接入点暂时满载” 等 |
| NETWORK_NOT_FOUND | ”无法连接,请稍后重试。” |
②的细节:SSID 与 tryConnectWifiEntry 匹配才弹 WifiPasswordDialog(isShowPasswordWrong=true) → 红字 “密码错误,请重新输入”(micar_connection_wifi_password_wrong,zh:150);已有弹窗显示中跳过(:64-66,commit 539d8de09 防重复弹)。广播发送方在 MIUI 定制框架(WifiService),本仓 grep 仅接收侧[待验证:frameworks 侧触发条件与 reason 集合]。引导页有孪生接收器(WlanProvisionDialogActivity.kt:52-88)。两个接收器均裸注册无 RECEIVER_EXPORTED 标志(:88/:112-120)。
CipherMismatch/超时:本仓零处理(grep 无 CipherMismatch;无连接超时看门狗——唯一 timeout 是 USER_RECENTLY_DISCONNECTED_TIMEOUT_MS=10s,只影响 canConnect)。四步握手 mismatch 的用户可见反馈完全依赖 ①/② 谁先到。
3405 的教训:用户点的是”已保存错误密码 entry”,旧逻辑静默拿旧密码重连 → framework 判定延迟 13~17s,期间零反馈。修复 = shouldEditBeforeConnect 拦截直弹密码框(commit 43313d80d)。
6. 详情页重连入口
详情页没有”连接”按钮,唯一重连路径 = 修改密码(MiCarWifiEntryDetailFragment:100-129,开放网禁用 :104)→ WifiPasswordDialog → MiCarWifiUtils.connect(带原 networkId,更新而非新建配置)→ goBack()(:123-124)。