本文共 8496 字,大约阅读时间需要 28 分钟。
1.场景
- 打开WiFi
- 打开WiFi热点(这时会把WiFi关闭)
- 改变WiFi热点的配置(这时会先关闭WiFi热点,再打开WiFi,最后再打开WiFi热点)
探讨下第3步WiFi和WiFi热点交替打开的逻辑实现。
2.流程梳理
TetherSettings.java
这个类是负责WiFi热点属性改变后的界面逻辑处理的,如下代码所示,改变配置点击保存后,这边会判断下如果mWifiConfig不为空并且当前WiFi热点为打开状态,那么先停止WiFi热点再打开WiFi热点,停止是在这个onClick里实现的,但重启WiFi热点这个onClick方法只是记了一个标志位。重启WiFi热点的逻辑是当接收到WiFi热点已关闭的广播后再判断下标志位再重启WiFi热点。
public void onClick(DialogInterface dialogInterface, int button) { if (button == DialogInterface.BUTTON_POSITIVE) { mWifiConfig = mDialog.getConfig(); if (mWifiConfig != null) { /** * if soft AP is stopped, bring up * else restart with new config * TODO: update config on a running access point when framework support is added */ if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED) { Log.d("TetheringSettings", "Wifi AP config changed while enabled, stop and restart"); mRestartWifiApAfterConfigChange = true; mCm.stopTethering(TETHERING_WIFI); } mWifiManager.setWifiApConfiguration(mWifiConfig); int index = WifiApDialog.getSecurityTypeIndex(mWifiConfig); mCreateNetwork.setSummary(String.format(getActivity().getString(CONFIG_SUBTEXT), mWifiConfig.SSID, mSecurityType[index])); } } } private class TetherChangeReceiver extends BroadcastReceiver { @Override public void onReceive(Context content, Intent intent) { String action = intent.getAction();... } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) { int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE, 0); if (state == WifiManager.WIFI_AP_STATE_DISABLED && mRestartWifiApAfterConfigChange) { mRestartWifiApAfterConfigChange = false; Log.d(TAG, "Restarting WifiAp due to prior config change."); startTethering(TETHERING_WIFI); } }
那么WiFi热点关闭时WiFi为何会自动打开呢?
WifiController
WiFi打开时所处状态
class StaEnabledState extends State { @Override public void enter() { mWifiStateMachine.setSupplicantRunning(true); } @Override public boolean processMessage(Message msg) { switch (msg.what) {... case CMD_SET_AP: if (msg.arg1 == 1) { // remeber that we were enabled mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_ENABLED); deferMessage(obtainMessage(msg.what, msg.arg1, 1, msg.obj)); transitionTo(mApStaDisabledState); } break;
这时候如果打开WiFi热点,那么WifiController就会记住当前WiFi状态为打开状态,并将打开WiFi热点的消息委托给ApStaDisabledState,就和WiFi没打开时逻辑一样,当然进入到ApStaDisabledState状态会将supplicant干掉,也就是WiFi会先关闭。
class ApStaDisabledState extends State { private int mDeferredEnableSerialNumber = 0; private boolean mHaveDeferredEnable = false; private long mDisabledTimestamp; @Override public void enter() { mWifiStateMachine.setSupplicantRunning(false); // Supplicant can't restart right away, so not the time we switched off mDisabledTimestamp = SystemClock.elapsedRealtime(); mDeferredEnableSerialNumber++; mHaveDeferredEnable = false; mWifiStateMachine.clearANQPCache(); }
WiFi热点打开以后会进入如下ApEnabledState状态,表示WiFi热点已打开
/** * Only transition out of this state when AP failed to start or AP is stopped. */ class ApEnabledState extends State { /** * Save the pending state when stopping the AP, so that it will transition * to the correct state when AP is stopped. This is to avoid a possible * race condition where the new state might try to update the driver/interface * state before AP is completely torn down. */ private State mPendingState = null; /** * Determine the next state based on the current settings (e.g. saved * wifi state). */ private State getNextWifiState() { if (mSettingsStore.getWifiSavedState() == WifiSettingsStore.WIFI_ENABLED) { return mDeviceActiveState; } if (mSettingsStore.isScanAlwaysAvailable()) { return mStaDisabledWithScanState; } return mApStaDisabledState; } @Override public boolean processMessage(Message msg) { switch (msg.what) { ... case CMD_SET_AP: if (msg.arg1 == 0) { mWifiStateMachine.setHostApRunning(null, false); mPendingState = getNextWifiState(); } break; case CMD_AP_STOPPED: if (mPendingState == null) { /** * Stop triggered internally, either tether notification * timed out or wifi is untethered for some reason. */ mPendingState = getNextWifiState(); } if (mPendingState == mDeviceActiveState && mDeviceIdle) { checkLocksAndTransitionWhenDeviceIdle(); } else { // go ahead and transition because we are not idle or we are not going // to the active state. transitionTo(mPendingState); } break;
这时候再接收到关闭WiFi热点的消息,这时会先将WiFi热点关掉,然后判断一下后续切换的状态。
/** * Determine the next state based on the current settings (e.g. saved * wifi state). */ private State getNextWifiState() { if (mSettingsStore.getWifiSavedState() == WifiSettingsStore.WIFI_ENABLED) { return mDeviceActiveState; } if (mSettingsStore.isScanAlwaysAvailable()) { return mStaDisabledWithScanState; } return mApStaDisabledState; }
由于最开始WiFi是处于打开状态并且已经记录了,所以这时候状态会切换到mDeviceActiveState。
切换流程是接收到WiFi热点已关闭的广播,然后发出CMD_AP_STOPPED消息并完成切换
mContext.registerReceiver( new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction();... } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) { int state = intent.getIntExtra( WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED); if (state == WifiManager.WIFI_AP_STATE_FAILED) { loge(TAG + "SoftAP start failed"); sendMessage(CMD_AP_START_FAILURE); } else if (state == WifiManager.WIFI_AP_STATE_DISABLED) { sendMessage(CMD_AP_STOPPED); }
case CMD_AP_STOPPED: if (mPendingState == null) { /** * Stop triggered internally, either tether notification * timed out or wifi is untethered for some reason. */ mPendingState = getNextWifiState(); } if (mPendingState == mDeviceActiveState && mDeviceIdle) { checkLocksAndTransitionWhenDeviceIdle(); } else { // go ahead and transition because we are not idle or we are not going // to the active state. transitionTo(mPendingState); } break;
切换到DeviceActiveState的enter方法,这边就开始了WiFi开启流程了。
/* Parent: StaEnabledState */ class DeviceActiveState extends State { @Override public void enter() { mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE); mWifiStateMachine.setHighPerfModeEnabled(false); }
3.总结
1代表打开WiFi热点,从WiFi打开状态先切换到热点关闭状态,打开WiFi热点的操作留给第2步
2代表处理打开WiFi热点的逻辑,从热点关闭状态切换到热点打开状态
3代表关闭WiFi热点,从热点打开状态切换到WiFi打开状态。
转载地址:https://jiatai.blog.csdn.net/article/details/83035808 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!