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,extra key_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_FAILUREWifiSettingsActivity#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)。