/*
|
* Copyright (C) 2013 The Android Open Source Project
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*/
|
|
package com.android.server.wifi;
|
|
import android.content.BroadcastReceiver;
|
import android.content.Context;
|
import android.content.Intent;
|
import android.content.IntentFilter;
|
import android.location.LocationManager;
|
import android.net.wifi.WifiManager;
|
import android.os.Handler;
|
import android.os.Looper;
|
import android.os.Message;
|
import android.os.SystemClock;
|
import android.provider.Settings;
|
import android.util.Log;
|
|
import com.android.internal.R;
|
import com.android.internal.util.Protocol;
|
import com.android.internal.util.State;
|
import com.android.internal.util.StateMachine;
|
import com.android.server.wifi.util.WifiPermissionsUtil;
|
|
/**
|
* WifiController is the class used to manage wifi state for various operating
|
* modes (normal, airplane, wifi hotspot, etc.).
|
*/
|
public class WifiController extends StateMachine {
|
private static final String TAG = "WifiController";
|
private static final boolean DBG = false;
|
private Context mContext;
|
private boolean mFirstUserSignOnSeen = false;
|
|
/**
|
* See {@link Settings.Global#WIFI_REENABLE_DELAY_MS}. This is the default value if a
|
* Settings.Global value is not present. This is the minimum time after wifi is disabled
|
* we'll act on an enable. Enable requests received before this delay will be deferred.
|
*/
|
private static final long DEFAULT_REENABLE_DELAY_MS = 500;
|
|
// Maximum limit to use for timeout delay if the value from overlay setting is too large.
|
private static final int MAX_RECOVERY_TIMEOUT_DELAY_MS = 4000;
|
|
// finding that delayed messages can sometimes be delivered earlier than expected
|
// probably rounding errors. add a margin to prevent problems
|
private static final long DEFER_MARGIN_MS = 5;
|
|
/* References to values tracked in WifiService */
|
private final ClientModeImpl mClientModeImpl;
|
private final Looper mClientModeImplLooper;
|
private final ActiveModeWarden mActiveModeWarden;
|
private final WifiSettingsStore mSettingsStore;
|
private final FrameworkFacade mFacade;
|
private final WifiPermissionsUtil mWifiPermissionsUtil;
|
|
private long mReEnableDelayMillis;
|
|
private int mRecoveryDelayMillis;
|
|
private static final int BASE = Protocol.BASE_WIFI_CONTROLLER;
|
|
static final int CMD_EMERGENCY_MODE_CHANGED = BASE + 1;
|
static final int CMD_SCAN_ALWAYS_MODE_CHANGED = BASE + 7;
|
static final int CMD_WIFI_TOGGLED = BASE + 8;
|
static final int CMD_AIRPLANE_TOGGLED = BASE + 9;
|
static final int CMD_SET_AP = BASE + 10;
|
static final int CMD_DEFERRED_TOGGLE = BASE + 11;
|
static final int CMD_AP_START_FAILURE = BASE + 13;
|
static final int CMD_EMERGENCY_CALL_STATE_CHANGED = BASE + 14;
|
static final int CMD_AP_STOPPED = BASE + 15;
|
static final int CMD_STA_START_FAILURE = BASE + 16;
|
// Command used to trigger a wifi stack restart when in active mode
|
static final int CMD_RECOVERY_RESTART_WIFI = BASE + 17;
|
// Internal command used to complete wifi stack restart
|
private static final int CMD_RECOVERY_RESTART_WIFI_CONTINUE = BASE + 18;
|
// Command to disable wifi when SelfRecovery is throttled or otherwise not doing full recovery
|
static final int CMD_RECOVERY_DISABLE_WIFI = BASE + 19;
|
static final int CMD_STA_STOPPED = BASE + 20;
|
static final int CMD_SCANNING_STOPPED = BASE + 21;
|
static final int CMD_DEFERRED_RECOVERY_RESTART_WIFI = BASE + 22;
|
|
private DefaultState mDefaultState = new DefaultState();
|
private StaEnabledState mStaEnabledState = new StaEnabledState();
|
private StaDisabledState mStaDisabledState = new StaDisabledState();
|
private StaDisabledWithScanState mStaDisabledWithScanState = new StaDisabledWithScanState();
|
private EcmState mEcmState = new EcmState();
|
|
private ScanOnlyModeManager.Listener mScanOnlyModeCallback = new ScanOnlyCallback();
|
private ClientModeManager.Listener mClientModeCallback = new ClientModeCallback();
|
|
WifiController(Context context, ClientModeImpl clientModeImpl, Looper clientModeImplLooper,
|
WifiSettingsStore wss, Looper wifiServiceLooper, FrameworkFacade f,
|
ActiveModeWarden amw, WifiPermissionsUtil wifiPermissionsUtil) {
|
super(TAG, wifiServiceLooper);
|
mFacade = f;
|
mContext = context;
|
mClientModeImpl = clientModeImpl;
|
mClientModeImplLooper = clientModeImplLooper;
|
mActiveModeWarden = amw;
|
mSettingsStore = wss;
|
mWifiPermissionsUtil = wifiPermissionsUtil;
|
|
// CHECKSTYLE:OFF IndentationCheck
|
addState(mDefaultState);
|
addState(mStaDisabledState, mDefaultState);
|
addState(mStaEnabledState, mDefaultState);
|
addState(mStaDisabledWithScanState, mDefaultState);
|
addState(mEcmState, mDefaultState);
|
// CHECKSTYLE:ON IndentationCheck
|
|
setLogRecSize(100);
|
setLogOnlyTransitions(false);
|
|
// register for state updates via callbacks (vs the intents registered below)
|
mActiveModeWarden.registerScanOnlyCallback(mScanOnlyModeCallback);
|
mActiveModeWarden.registerClientModeCallback(mClientModeCallback);
|
|
readWifiReEnableDelay();
|
readWifiRecoveryDelay();
|
}
|
|
@Override
|
public void start() {
|
boolean isAirplaneModeOn = mSettingsStore.isAirplaneModeOn();
|
boolean isWifiEnabled = mSettingsStore.isWifiToggleEnabled();
|
boolean isScanningAlwaysAvailable = mSettingsStore.isScanAlwaysAvailable();
|
boolean isLocationModeActive = mWifiPermissionsUtil.isLocationModeEnabled();
|
|
log("isAirplaneModeOn = " + isAirplaneModeOn
|
+ ", isWifiEnabled = " + isWifiEnabled
|
+ ", isScanningAvailable = " + isScanningAlwaysAvailable
|
+ ", isLocationModeActive = " + isLocationModeActive);
|
|
if (checkScanOnlyModeAvailable()) {
|
setInitialState(mStaDisabledWithScanState);
|
} else {
|
setInitialState(mStaDisabledState);
|
}
|
IntentFilter filter = new IntentFilter();
|
filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
|
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
|
filter.addAction(LocationManager.MODE_CHANGED_ACTION);
|
mContext.registerReceiver(
|
new BroadcastReceiver() {
|
@Override
|
public void onReceive(Context context, Intent intent) {
|
String action = intent.getAction();
|
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) {
|
Log.e(TAG, "SoftAP start failed");
|
sendMessage(CMD_AP_START_FAILURE);
|
} else if (state == WifiManager.WIFI_AP_STATE_DISABLED) {
|
sendMessage(CMD_AP_STOPPED);
|
}
|
} else if (action.equals(LocationManager.MODE_CHANGED_ACTION)) {
|
// Location mode has been toggled... trigger with the scan change
|
// update to make sure we are in the correct mode
|
sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED);
|
}
|
}
|
},
|
new IntentFilter(filter));
|
super.start();
|
}
|
|
private boolean checkScanOnlyModeAvailable() {
|
// first check if Location service is disabled, if so return false
|
if (!mWifiPermissionsUtil.isLocationModeEnabled()) {
|
return false;
|
}
|
return mSettingsStore.isScanAlwaysAvailable();
|
}
|
|
/**
|
* Listener used to receive scan mode updates - really needed for disabled updates to trigger
|
* mode changes.
|
*/
|
private class ScanOnlyCallback implements ScanOnlyModeManager.Listener {
|
@Override
|
public void onStateChanged(int state) {
|
if (state == WifiManager.WIFI_STATE_UNKNOWN) {
|
Log.d(TAG, "ScanOnlyMode unexpected failure: state unknown");
|
} else if (state == WifiManager.WIFI_STATE_DISABLED) {
|
Log.d(TAG, "ScanOnlyMode stopped");
|
sendMessage(CMD_SCANNING_STOPPED);
|
} else if (state == WifiManager.WIFI_STATE_ENABLED) {
|
// scan mode is ready to go
|
Log.d(TAG, "scan mode active");
|
} else {
|
Log.d(TAG, "unexpected state update: " + state);
|
}
|
}
|
}
|
|
/**
|
* Listener used to receive client mode updates
|
*/
|
private class ClientModeCallback implements ClientModeManager.Listener {
|
@Override
|
public void onStateChanged(int state) {
|
if (state == WifiManager.WIFI_STATE_UNKNOWN) {
|
logd("ClientMode unexpected failure: state unknown");
|
sendMessage(CMD_STA_START_FAILURE);
|
} else if (state == WifiManager.WIFI_STATE_DISABLED) {
|
logd("ClientMode stopped");
|
sendMessage(CMD_STA_STOPPED);
|
} else if (state == WifiManager.WIFI_STATE_ENABLED) {
|
// scan mode is ready to go
|
logd("client mode active");
|
} else {
|
logd("unexpected state update: " + state);
|
}
|
}
|
}
|
|
private void readWifiReEnableDelay() {
|
mReEnableDelayMillis = mFacade.getLongSetting(mContext,
|
Settings.Global.WIFI_REENABLE_DELAY_MS, DEFAULT_REENABLE_DELAY_MS);
|
}
|
|
private void readWifiRecoveryDelay() {
|
mRecoveryDelayMillis = mContext.getResources().getInteger(
|
R.integer.config_wifi_framework_recovery_timeout_delay);
|
if (mRecoveryDelayMillis > MAX_RECOVERY_TIMEOUT_DELAY_MS) {
|
mRecoveryDelayMillis = MAX_RECOVERY_TIMEOUT_DELAY_MS;
|
Log.w(TAG, "Overriding timeout delay with maximum limit value");
|
}
|
}
|
|
class DefaultState extends State {
|
@Override
|
public boolean processMessage(Message msg) {
|
switch (msg.what) {
|
case CMD_SCAN_ALWAYS_MODE_CHANGED:
|
case CMD_WIFI_TOGGLED:
|
case CMD_AP_START_FAILURE:
|
case CMD_SCANNING_STOPPED:
|
case CMD_STA_STOPPED:
|
case CMD_STA_START_FAILURE:
|
case CMD_RECOVERY_RESTART_WIFI_CONTINUE:
|
case CMD_DEFERRED_RECOVERY_RESTART_WIFI:
|
break;
|
case CMD_RECOVERY_DISABLE_WIFI:
|
log("Recovery has been throttled, disable wifi");
|
mActiveModeWarden.shutdownWifi();
|
transitionTo(mStaDisabledState);
|
break;
|
case CMD_RECOVERY_RESTART_WIFI:
|
deferMessage(obtainMessage(CMD_DEFERRED_RECOVERY_RESTART_WIFI));
|
mActiveModeWarden.shutdownWifi();
|
transitionTo(mStaDisabledState);
|
break;
|
case CMD_DEFERRED_TOGGLE:
|
log("DEFERRED_TOGGLE ignored due to state change");
|
break;
|
case CMD_SET_AP:
|
// note: CMD_SET_AP is handled/dropped in ECM mode - will not start here
|
if (msg.arg1 == 1) {
|
SoftApModeConfiguration config = (SoftApModeConfiguration) msg.obj;
|
mActiveModeWarden.enterSoftAPMode((SoftApModeConfiguration) msg.obj);
|
} else {
|
mActiveModeWarden.stopSoftAPMode(msg.arg2);
|
}
|
break;
|
case CMD_AIRPLANE_TOGGLED:
|
if (mSettingsStore.isAirplaneModeOn()) {
|
log("Airplane mode toggled, shutdown all modes");
|
mActiveModeWarden.shutdownWifi();
|
transitionTo(mStaDisabledState);
|
} else {
|
log("Airplane mode disabled, determine next state");
|
if (mSettingsStore.isWifiToggleEnabled()) {
|
transitionTo(mStaEnabledState);
|
} else if (checkScanOnlyModeAvailable()) {
|
transitionTo(mStaDisabledWithScanState);
|
}
|
// wifi should remain disabled, do not need to transition
|
}
|
break;
|
case CMD_EMERGENCY_CALL_STATE_CHANGED:
|
case CMD_EMERGENCY_MODE_CHANGED:
|
if (msg.arg1 == 1) {
|
transitionTo(mEcmState);
|
}
|
break;
|
case CMD_AP_STOPPED:
|
log("SoftAp mode disabled, determine next state");
|
if (mSettingsStore.isWifiToggleEnabled()) {
|
transitionTo(mStaEnabledState);
|
} else if (checkScanOnlyModeAvailable()) {
|
transitionTo(mStaDisabledWithScanState);
|
}
|
// wifi should remain disabled, do not need to transition
|
break;
|
default:
|
throw new RuntimeException("WifiController.handleMessage " + msg.what);
|
}
|
return HANDLED;
|
}
|
|
}
|
|
class StaDisabledState extends State {
|
private int mDeferredEnableSerialNumber = 0;
|
private boolean mHaveDeferredEnable = false;
|
private long mDisabledTimestamp;
|
|
@Override
|
public void enter() {
|
mActiveModeWarden.disableWifi();
|
// Supplicant can't restart right away, so note the time we switched off
|
mDisabledTimestamp = SystemClock.elapsedRealtime();
|
mDeferredEnableSerialNumber++;
|
mHaveDeferredEnable = false;
|
}
|
@Override
|
public boolean processMessage(Message msg) {
|
switch (msg.what) {
|
case CMD_WIFI_TOGGLED:
|
if (mSettingsStore.isWifiToggleEnabled()) {
|
if (doDeferEnable(msg)) {
|
if (mHaveDeferredEnable) {
|
// have 2 toggles now, inc serial number and ignore both
|
mDeferredEnableSerialNumber++;
|
}
|
mHaveDeferredEnable = !mHaveDeferredEnable;
|
break;
|
}
|
transitionTo(mStaEnabledState);
|
} else if (checkScanOnlyModeAvailable()) {
|
// only go to scan mode if we aren't in airplane mode
|
if (mSettingsStore.isAirplaneModeOn()) {
|
transitionTo(mStaDisabledWithScanState);
|
}
|
}
|
break;
|
case CMD_SCAN_ALWAYS_MODE_CHANGED:
|
if (checkScanOnlyModeAvailable()) {
|
transitionTo(mStaDisabledWithScanState);
|
break;
|
}
|
break;
|
case CMD_SET_AP:
|
if (msg.arg1 == 1) {
|
// remember that we were disabled, but pass the command up to start softap
|
mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_DISABLED);
|
}
|
return NOT_HANDLED;
|
case CMD_DEFERRED_TOGGLE:
|
if (msg.arg1 != mDeferredEnableSerialNumber) {
|
log("DEFERRED_TOGGLE ignored due to serial mismatch");
|
break;
|
}
|
log("DEFERRED_TOGGLE handled");
|
sendMessage((Message)(msg.obj));
|
break;
|
case CMD_DEFERRED_RECOVERY_RESTART_WIFI:
|
// wait mRecoveryDelayMillis for letting driver clean reset.
|
sendMessageDelayed(CMD_RECOVERY_RESTART_WIFI_CONTINUE, mRecoveryDelayMillis);
|
break;
|
case CMD_RECOVERY_RESTART_WIFI_CONTINUE:
|
if (mSettingsStore.isWifiToggleEnabled()) {
|
// wifi is currently disabled but the toggle is on, must have had an
|
// interface down before the recovery triggered
|
transitionTo(mStaEnabledState);
|
break;
|
} else if (checkScanOnlyModeAvailable()) {
|
transitionTo(mStaDisabledWithScanState);
|
break;
|
}
|
break;
|
default:
|
return NOT_HANDLED;
|
}
|
return HANDLED;
|
}
|
|
private boolean doDeferEnable(Message msg) {
|
long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp;
|
if (delaySoFar >= mReEnableDelayMillis) {
|
return false;
|
}
|
|
log("WifiController msg " + msg + " deferred for " +
|
(mReEnableDelayMillis - delaySoFar) + "ms");
|
|
// need to defer this action.
|
Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE);
|
deferredMsg.obj = Message.obtain(msg);
|
deferredMsg.arg1 = ++mDeferredEnableSerialNumber;
|
sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS);
|
return true;
|
}
|
|
}
|
|
class StaEnabledState extends State {
|
@Override
|
public void enter() {
|
log("StaEnabledState.enter()");
|
mActiveModeWarden.enterClientMode();
|
}
|
|
@Override
|
public boolean processMessage(Message msg) {
|
switch (msg.what) {
|
case CMD_WIFI_TOGGLED:
|
if (! mSettingsStore.isWifiToggleEnabled()) {
|
if (checkScanOnlyModeAvailable()) {
|
transitionTo(mStaDisabledWithScanState);
|
} else {
|
transitionTo(mStaDisabledState);
|
}
|
}
|
break;
|
case CMD_AIRPLANE_TOGGLED:
|
// airplane mode toggled on is handled in the default state
|
if (mSettingsStore.isAirplaneModeOn()) {
|
return NOT_HANDLED;
|
} else {
|
// when airplane mode is toggled off, but wifi is on, we can keep it on
|
log("airplane mode toggled - and airplane mode is off. return handled");
|
return HANDLED;
|
}
|
case CMD_STA_START_FAILURE:
|
if (!checkScanOnlyModeAvailable()) {
|
transitionTo(mStaDisabledState);
|
} else {
|
transitionTo(mStaDisabledWithScanState);
|
}
|
break;
|
case CMD_SET_AP:
|
if (msg.arg1 == 1) {
|
// remember that we were enabled, but pass the command up to start softap
|
mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_ENABLED);
|
}
|
return NOT_HANDLED;
|
case CMD_AP_START_FAILURE:
|
case CMD_AP_STOPPED:
|
// already in a wifi mode, no need to check where we should go with softap
|
// stopped
|
break;
|
case CMD_STA_STOPPED:
|
// Client mode stopped. head to Disabled to wait for next command
|
transitionTo(mStaDisabledState);
|
break;
|
case CMD_RECOVERY_RESTART_WIFI:
|
final String bugTitle;
|
final String bugDetail;
|
if (msg.arg1 < SelfRecovery.REASON_STRINGS.length && msg.arg1 >= 0) {
|
bugDetail = SelfRecovery.REASON_STRINGS[msg.arg1];
|
bugTitle = "Wi-Fi BugReport: " + bugDetail;
|
} else {
|
bugDetail = "";
|
bugTitle = "Wi-Fi BugReport";
|
}
|
if (msg.arg1 != SelfRecovery.REASON_LAST_RESORT_WATCHDOG) {
|
(new Handler(mClientModeImplLooper)).post(() -> {
|
mClientModeImpl.takeBugReport(bugTitle, bugDetail);
|
});
|
}
|
// after the bug report trigger, more handling needs to be done
|
return NOT_HANDLED;
|
default:
|
return NOT_HANDLED;
|
}
|
return HANDLED;
|
}
|
}
|
|
class StaDisabledWithScanState extends State {
|
private int mDeferredEnableSerialNumber = 0;
|
private boolean mHaveDeferredEnable = false;
|
private long mDisabledTimestamp;
|
|
@Override
|
public void enter() {
|
// now trigger the actual mode switch in ActiveModeWarden
|
mActiveModeWarden.enterScanOnlyMode();
|
|
// TODO b/71559473: remove the defered enable after mode management changes are complete
|
// Supplicant can't restart right away, so not the time we switched off
|
mDisabledTimestamp = SystemClock.elapsedRealtime();
|
mDeferredEnableSerialNumber++;
|
mHaveDeferredEnable = false;
|
}
|
|
@Override
|
public boolean processMessage(Message msg) {
|
switch (msg.what) {
|
case CMD_WIFI_TOGGLED:
|
if (mSettingsStore.isWifiToggleEnabled()) {
|
if (doDeferEnable(msg)) {
|
if (mHaveDeferredEnable) {
|
// have 2 toggles now, inc serial number and ignore both
|
mDeferredEnableSerialNumber++;
|
}
|
mHaveDeferredEnable = !mHaveDeferredEnable;
|
break;
|
}
|
transitionTo(mStaEnabledState);
|
}
|
break;
|
case CMD_SCAN_ALWAYS_MODE_CHANGED:
|
if (!checkScanOnlyModeAvailable()) {
|
log("StaDisabledWithScanState: scan no longer available");
|
transitionTo(mStaDisabledState);
|
}
|
break;
|
case CMD_SET_AP:
|
if (msg.arg1 == 1) {
|
// remember that we were disabled, but pass the command up to start softap
|
mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_DISABLED);
|
}
|
return NOT_HANDLED;
|
case CMD_DEFERRED_TOGGLE:
|
if (msg.arg1 != mDeferredEnableSerialNumber) {
|
log("DEFERRED_TOGGLE ignored due to serial mismatch");
|
break;
|
}
|
logd("DEFERRED_TOGGLE handled");
|
sendMessage((Message)(msg.obj));
|
break;
|
case CMD_AP_START_FAILURE:
|
case CMD_AP_STOPPED:
|
// already in a wifi mode, no need to check where we should go with softap
|
// stopped
|
break;
|
case CMD_SCANNING_STOPPED:
|
// stopped due to interface destruction - return to disabled and wait
|
log("WifiController: SCANNING_STOPPED when in scan mode -> StaDisabled");
|
transitionTo(mStaDisabledState);
|
break;
|
default:
|
return NOT_HANDLED;
|
}
|
return HANDLED;
|
}
|
|
private boolean doDeferEnable(Message msg) {
|
long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp;
|
if (delaySoFar >= mReEnableDelayMillis) {
|
return false;
|
}
|
|
log("WifiController msg " + msg + " deferred for " +
|
(mReEnableDelayMillis - delaySoFar) + "ms");
|
|
// need to defer this action.
|
Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE);
|
deferredMsg.obj = Message.obtain(msg);
|
deferredMsg.arg1 = ++mDeferredEnableSerialNumber;
|
sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS);
|
return true;
|
}
|
|
}
|
|
/**
|
* Determine the next state based on the current settings (e.g. saved
|
* wifi state).
|
*/
|
private State getNextWifiState() {
|
if (mSettingsStore.getWifiSavedState() == WifiSettingsStore.WIFI_ENABLED) {
|
return mStaEnabledState;
|
}
|
|
if (checkScanOnlyModeAvailable()) {
|
return mStaDisabledWithScanState;
|
}
|
|
return mStaDisabledState;
|
}
|
|
class EcmState extends State {
|
// we can enter EcmState either because an emergency call started or because
|
// emergency callback mode started. This count keeps track of how many such
|
// events happened; so we can exit after all are undone
|
|
private int mEcmEntryCount;
|
@Override
|
public void enter() {
|
mActiveModeWarden.stopSoftAPMode(WifiManager.IFACE_IP_MODE_UNSPECIFIED);
|
boolean configWiFiDisableInECBM =
|
mFacade.getConfigWiFiDisableInECBM(mContext);
|
log("WifiController msg getConfigWiFiDisableInECBM "
|
+ configWiFiDisableInECBM);
|
if (configWiFiDisableInECBM) {
|
mActiveModeWarden.shutdownWifi();
|
}
|
mEcmEntryCount = 1;
|
}
|
|
/**
|
* Handles messages received while in EcmMode.
|
*/
|
@Override
|
public boolean processMessage(Message msg) {
|
switch (msg.what) {
|
case CMD_EMERGENCY_CALL_STATE_CHANGED:
|
if (msg.arg1 == 1) {
|
// nothing to do - just says emergency call started
|
mEcmEntryCount++;
|
} else if (msg.arg1 == 0) {
|
// emergency call ended
|
decrementCountAndReturnToAppropriateState();
|
}
|
return HANDLED;
|
case CMD_EMERGENCY_MODE_CHANGED:
|
if (msg.arg1 == 1) {
|
// Transitioned into emergency callback mode
|
mEcmEntryCount++;
|
} else if (msg.arg1 == 0) {
|
// out of emergency callback mode
|
decrementCountAndReturnToAppropriateState();
|
}
|
return HANDLED;
|
case CMD_RECOVERY_RESTART_WIFI:
|
case CMD_RECOVERY_DISABLE_WIFI:
|
// do not want to restart wifi if we are in emergency mode
|
return HANDLED;
|
case CMD_AP_STOPPED:
|
case CMD_SCANNING_STOPPED:
|
case CMD_STA_STOPPED:
|
// do not want to trigger a mode switch if we are in emergency mode
|
return HANDLED;
|
case CMD_SET_AP:
|
// do not want to start softap if we are in emergency mode
|
return HANDLED;
|
default:
|
return NOT_HANDLED;
|
}
|
}
|
|
private void decrementCountAndReturnToAppropriateState() {
|
boolean exitEcm = false;
|
|
if (mEcmEntryCount == 0) {
|
loge("mEcmEntryCount is 0; exiting Ecm");
|
exitEcm = true;
|
} else if (--mEcmEntryCount == 0) {
|
exitEcm = true;
|
}
|
|
if (exitEcm) {
|
if (mSettingsStore.isWifiToggleEnabled()) {
|
transitionTo(mStaEnabledState);
|
} else if (checkScanOnlyModeAvailable()) {
|
transitionTo(mStaDisabledWithScanState);
|
} else {
|
transitionTo(mStaDisabledState);
|
}
|
}
|
}
|
}
|
}
|