summaryrefslogtreecommitdiffstats
path: root/services/core/java/com/android/server/wifi/WifiController.java
diff options
context:
space:
mode:
Diffstat (limited to 'services/core/java/com/android/server/wifi/WifiController.java')
-rw-r--r--services/core/java/com/android/server/wifi/WifiController.java751
1 files changed, 751 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/wifi/WifiController.java b/services/core/java/com/android/server/wifi/WifiController.java
new file mode 100644
index 0000000..a3d514e
--- /dev/null
+++ b/services/core/java/com/android/server/wifi/WifiController.java
@@ -0,0 +1,751 @@
+/*
+ * 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.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import static android.net.wifi.WifiManager.WIFI_MODE_FULL;
+import static android.net.wifi.WifiManager.WIFI_MODE_FULL_HIGH_PERF;
+import static android.net.wifi.WifiManager.WIFI_MODE_SCAN_ONLY;
+import android.net.wifi.WifiStateMachine;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.SystemClock;
+import android.os.WorkSource;
+import android.provider.Settings;
+import android.util.Slog;
+
+import com.android.internal.util.Protocol;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+import com.android.server.wifi.WifiService.LockList;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+class WifiController extends StateMachine {
+ private static final String TAG = "WifiController";
+ private static final boolean DBG = false;
+ private Context mContext;
+ private boolean mScreenOff;
+ private boolean mDeviceIdle;
+ private int mPluggedType;
+ private int mStayAwakeConditions;
+ private long mIdleMillis;
+ private int mSleepPolicy;
+ private boolean mFirstUserSignOnSeen = false;
+
+ private AlarmManager mAlarmManager;
+ private PendingIntent mIdleIntent;
+ private static final int IDLE_REQUEST = 0;
+
+ /**
+ * See {@link Settings.Global#WIFI_IDLE_MS}. This is the default value if a
+ * Settings.Global value is not present. This timeout value is chosen as
+ * the approximate point at which the battery drain caused by Wi-Fi
+ * being enabled but not active exceeds the battery drain caused by
+ * re-establishing a connection to the mobile data network.
+ */
+ private static final long DEFAULT_IDLE_MS = 15 * 60 * 1000; /* 15 minutes */
+
+ /**
+ * 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;
+
+ // 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;
+
+ NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
+
+ private static final String ACTION_DEVICE_IDLE =
+ "com.android.server.WifiManager.action.DEVICE_IDLE";
+
+ /* References to values tracked in WifiService */
+ final WifiStateMachine mWifiStateMachine;
+ final WifiSettingsStore mSettingsStore;
+ final LockList mLocks;
+
+ /**
+ * Temporary for computing UIDS that are responsible for starting WIFI.
+ * Protected by mWifiStateTracker lock.
+ */
+ private final WorkSource mTmpWorkSource = new WorkSource();
+
+ private long mReEnableDelayMillis;
+
+ private static final int BASE = Protocol.BASE_WIFI_CONTROLLER;
+
+ static final int CMD_EMERGENCY_MODE_CHANGED = BASE + 1;
+ static final int CMD_SCREEN_ON = BASE + 2;
+ static final int CMD_SCREEN_OFF = BASE + 3;
+ static final int CMD_BATTERY_CHANGED = BASE + 4;
+ static final int CMD_DEVICE_IDLE = BASE + 5;
+ static final int CMD_LOCKS_CHANGED = BASE + 6;
+ 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_USER_PRESENT = BASE + 12;
+
+ private DefaultState mDefaultState = new DefaultState();
+ private StaEnabledState mStaEnabledState = new StaEnabledState();
+ private ApStaDisabledState mApStaDisabledState = new ApStaDisabledState();
+ private StaDisabledWithScanState mStaDisabledWithScanState = new StaDisabledWithScanState();
+ private ApEnabledState mApEnabledState = new ApEnabledState();
+ private DeviceActiveState mDeviceActiveState = new DeviceActiveState();
+ private DeviceInactiveState mDeviceInactiveState = new DeviceInactiveState();
+ private ScanOnlyLockHeldState mScanOnlyLockHeldState = new ScanOnlyLockHeldState();
+ private FullLockHeldState mFullLockHeldState = new FullLockHeldState();
+ private FullHighPerfLockHeldState mFullHighPerfLockHeldState = new FullHighPerfLockHeldState();
+ private NoLockHeldState mNoLockHeldState = new NoLockHeldState();
+ private EcmState mEcmState = new EcmState();
+
+ WifiController(Context context, WifiService service, Looper looper) {
+ super(TAG, looper);
+ mContext = context;
+ mWifiStateMachine = service.mWifiStateMachine;
+ mSettingsStore = service.mSettingsStore;
+ mLocks = service.mLocks;
+
+ mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+ Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
+ mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
+
+ addState(mDefaultState);
+ addState(mApStaDisabledState, mDefaultState);
+ addState(mStaEnabledState, mDefaultState);
+ addState(mDeviceActiveState, mStaEnabledState);
+ addState(mDeviceInactiveState, mStaEnabledState);
+ addState(mScanOnlyLockHeldState, mDeviceInactiveState);
+ addState(mFullLockHeldState, mDeviceInactiveState);
+ addState(mFullHighPerfLockHeldState, mDeviceInactiveState);
+ addState(mNoLockHeldState, mDeviceInactiveState);
+ addState(mStaDisabledWithScanState, mDefaultState);
+ addState(mApEnabledState, mDefaultState);
+ addState(mEcmState, mDefaultState);
+ if (mSettingsStore.isScanAlwaysAvailable()) {
+ setInitialState(mStaDisabledWithScanState);
+ } else {
+ setInitialState(mApStaDisabledState);
+ }
+ setLogRecSize(100);
+ setLogOnlyTransitions(false);
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_DEVICE_IDLE);
+ filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ mContext.registerReceiver(
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(ACTION_DEVICE_IDLE)) {
+ sendMessage(CMD_DEVICE_IDLE);
+ } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+ mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
+ WifiManager.EXTRA_NETWORK_INFO);
+ }
+ }
+ },
+ new IntentFilter(filter));
+
+ initializeAndRegisterForSettingsChange(looper);
+ }
+
+ private void initializeAndRegisterForSettingsChange(Looper looper) {
+ Handler handler = new Handler(looper);
+ readStayAwakeConditions();
+ registerForStayAwakeModeChange(handler);
+ readWifiIdleTime();
+ registerForWifiIdleTimeChange(handler);
+ readWifiSleepPolicy();
+ registerForWifiSleepPolicyChange(handler);
+ readWifiReEnableDelay();
+ }
+
+ private void readStayAwakeConditions() {
+ mStayAwakeConditions = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
+ }
+
+ private void readWifiIdleTime() {
+ mIdleMillis = Settings.Global.getLong(mContext.getContentResolver(),
+ Settings.Global.WIFI_IDLE_MS, DEFAULT_IDLE_MS);
+ }
+
+ private void readWifiSleepPolicy() {
+ mSleepPolicy = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.WIFI_SLEEP_POLICY,
+ Settings.Global.WIFI_SLEEP_POLICY_NEVER);
+ }
+
+ private void readWifiReEnableDelay() {
+ mReEnableDelayMillis = Settings.Global.getLong(mContext.getContentResolver(),
+ Settings.Global.WIFI_REENABLE_DELAY_MS, DEFAULT_REENABLE_DELAY_MS);
+ }
+
+ /**
+ * Observes settings changes to scan always mode.
+ */
+ private void registerForStayAwakeModeChange(Handler handler) {
+ ContentObserver contentObserver = new ContentObserver(handler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ readStayAwakeConditions();
+ }
+ };
+
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.STAY_ON_WHILE_PLUGGED_IN),
+ false, contentObserver);
+ }
+
+ /**
+ * Observes settings changes to scan always mode.
+ */
+ private void registerForWifiIdleTimeChange(Handler handler) {
+ ContentObserver contentObserver = new ContentObserver(handler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ readWifiIdleTime();
+ }
+ };
+
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.WIFI_IDLE_MS),
+ false, contentObserver);
+ }
+
+ /**
+ * Observes changes to wifi sleep policy
+ */
+ private void registerForWifiSleepPolicyChange(Handler handler) {
+ ContentObserver contentObserver = new ContentObserver(handler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ readWifiSleepPolicy();
+ }
+ };
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.WIFI_SLEEP_POLICY),
+ false, contentObserver);
+ }
+
+ /**
+ * Determines whether the Wi-Fi chipset should stay awake or be put to
+ * sleep. Looks at the setting for the sleep policy and the current
+ * conditions.
+ *
+ * @see #shouldDeviceStayAwake(int)
+ */
+ private boolean shouldWifiStayAwake(int pluggedType) {
+ if (mSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER) {
+ // Never sleep
+ return true;
+ } else if ((mSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) &&
+ (pluggedType != 0)) {
+ // Never sleep while plugged, and we're plugged
+ return true;
+ } else {
+ // Default
+ return shouldDeviceStayAwake(pluggedType);
+ }
+ }
+
+ /**
+ * Determine whether the bit value corresponding to {@code pluggedType} is set in
+ * the bit string mStayAwakeConditions. This determines whether the device should
+ * stay awake based on the current plugged type.
+ *
+ * @param pluggedType the type of plug (USB, AC, or none) for which the check is
+ * being made
+ * @return {@code true} if {@code pluggedType} indicates that the device is
+ * supposed to stay awake, {@code false} otherwise.
+ */
+ private boolean shouldDeviceStayAwake(int pluggedType) {
+ return (mStayAwakeConditions & pluggedType) != 0;
+ }
+
+ private void updateBatteryWorkSource() {
+ mTmpWorkSource.clear();
+ if (mDeviceIdle) {
+ mLocks.updateWorkSource(mTmpWorkSource);
+ }
+ mWifiStateMachine.updateBatteryWorkSource(mTmpWorkSource);
+ }
+
+ class DefaultState extends State {
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case CMD_SCREEN_ON:
+ mAlarmManager.cancel(mIdleIntent);
+ mScreenOff = false;
+ mDeviceIdle = false;
+ updateBatteryWorkSource();
+ break;
+ case CMD_SCREEN_OFF:
+ mScreenOff = true;
+ /*
+ * Set a timer to put Wi-Fi to sleep, but only if the screen is off
+ * AND the "stay on while plugged in" setting doesn't match the
+ * current power conditions (i.e, not plugged in, plugged in to USB,
+ * or plugged in to AC).
+ */
+ if (!shouldWifiStayAwake(mPluggedType)) {
+ //Delayed shutdown if wifi is connected
+ if (mNetworkInfo.getDetailedState() ==
+ NetworkInfo.DetailedState.CONNECTED) {
+ if (DBG) Slog.d(TAG, "set idle timer: " + mIdleMillis + " ms");
+ mAlarmManager.set(AlarmManager.RTC_WAKEUP,
+ System.currentTimeMillis() + mIdleMillis, mIdleIntent);
+ } else {
+ sendMessage(CMD_DEVICE_IDLE);
+ }
+ }
+ break;
+ case CMD_DEVICE_IDLE:
+ mDeviceIdle = true;
+ updateBatteryWorkSource();
+ break;
+ case CMD_BATTERY_CHANGED:
+ /*
+ * Set a timer to put Wi-Fi to sleep, but only if the screen is off
+ * AND we are transitioning from a state in which the device was supposed
+ * to stay awake to a state in which it is not supposed to stay awake.
+ * If "stay awake" state is not changing, we do nothing, to avoid resetting
+ * the already-set timer.
+ */
+ int pluggedType = msg.arg1;
+ if (DBG) Slog.d(TAG, "battery changed pluggedType: " + pluggedType);
+ if (mScreenOff && shouldWifiStayAwake(mPluggedType) &&
+ !shouldWifiStayAwake(pluggedType)) {
+ long triggerTime = System.currentTimeMillis() + mIdleMillis;
+ if (DBG) Slog.d(TAG, "set idle timer for " + mIdleMillis + "ms");
+ mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
+ }
+
+ mPluggedType = pluggedType;
+ break;
+ case CMD_SET_AP:
+ case CMD_SCAN_ALWAYS_MODE_CHANGED:
+ case CMD_LOCKS_CHANGED:
+ case CMD_WIFI_TOGGLED:
+ case CMD_AIRPLANE_TOGGLED:
+ case CMD_EMERGENCY_MODE_CHANGED:
+ break;
+ case CMD_USER_PRESENT:
+ mFirstUserSignOnSeen = true;
+ break;
+ case CMD_DEFERRED_TOGGLE:
+ log("DEFERRED_TOGGLE ignored due to state change");
+ break;
+ default:
+ throw new RuntimeException("WifiController.handleMessage " + msg.what);
+ }
+ return HANDLED;
+ }
+
+ }
+
+ 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;
+ }
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case CMD_WIFI_TOGGLED:
+ case CMD_AIRPLANE_TOGGLED:
+ if (mSettingsStore.isWifiToggleEnabled()) {
+ if (doDeferEnable(msg)) {
+ if (mHaveDeferredEnable) {
+ // have 2 toggles now, inc serial number an ignore both
+ mDeferredEnableSerialNumber++;
+ }
+ mHaveDeferredEnable = !mHaveDeferredEnable;
+ break;
+ }
+ if (mDeviceIdle == false) {
+ transitionTo(mDeviceActiveState);
+ } else {
+ checkLocksAndTransitionWhenDeviceIdle();
+ }
+ }
+ break;
+ case CMD_SCAN_ALWAYS_MODE_CHANGED:
+ if (mSettingsStore.isScanAlwaysAvailable()) {
+ transitionTo(mStaDisabledWithScanState);
+ }
+ break;
+ case CMD_SET_AP:
+ if (msg.arg1 == 1) {
+ mWifiStateMachine.setHostApRunning((WifiConfiguration) msg.obj,
+ true);
+ transitionTo(mApEnabledState);
+ }
+ break;
+ 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;
+ 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() {
+ mWifiStateMachine.setSupplicantRunning(true);
+ }
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case CMD_WIFI_TOGGLED:
+ if (! mSettingsStore.isWifiToggleEnabled()) {
+ if (mSettingsStore.isScanAlwaysAvailable()) {
+ transitionTo(mStaDisabledWithScanState);
+ } else {
+ transitionTo(mApStaDisabledState);
+ }
+ }
+ break;
+ case CMD_AIRPLANE_TOGGLED:
+ /* When wi-fi is turned off due to airplane,
+ * disable entirely (including scan)
+ */
+ if (! mSettingsStore.isWifiToggleEnabled()) {
+ transitionTo(mApStaDisabledState);
+ }
+ break;
+ case CMD_EMERGENCY_MODE_CHANGED:
+ if (msg.arg1 == 1) {
+ transitionTo(mEcmState);
+ break;
+ }
+ 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() {
+ mWifiStateMachine.setSupplicantRunning(true);
+ mWifiStateMachine.setOperationalMode(WifiStateMachine.SCAN_ONLY_WITH_WIFI_OFF_MODE);
+ mWifiStateMachine.setDriverStart(true);
+ // 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;
+ }
+ if (mDeviceIdle == false) {
+ transitionTo(mDeviceActiveState);
+ } else {
+ checkLocksAndTransitionWhenDeviceIdle();
+ }
+ }
+ break;
+ case CMD_AIRPLANE_TOGGLED:
+ if (mSettingsStore.isAirplaneModeOn() &&
+ ! mSettingsStore.isWifiToggleEnabled()) {
+ transitionTo(mApStaDisabledState);
+ }
+ case CMD_SCAN_ALWAYS_MODE_CHANGED:
+ if (! mSettingsStore.isScanAlwaysAvailable()) {
+ transitionTo(mApStaDisabledState);
+ }
+ break;
+ case CMD_SET_AP:
+ // Before starting tethering, turn off supplicant for scan mode
+ if (msg.arg1 == 1) {
+ deferMessage(msg);
+ transitionTo(mApStaDisabledState);
+ }
+ break;
+ 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;
+ 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 ApEnabledState extends State {
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case CMD_AIRPLANE_TOGGLED:
+ if (mSettingsStore.isAirplaneModeOn()) {
+ mWifiStateMachine.setHostApRunning(null, false);
+ transitionTo(mApStaDisabledState);
+ }
+ break;
+ case CMD_SET_AP:
+ if (msg.arg1 == 0) {
+ mWifiStateMachine.setHostApRunning(null, false);
+ transitionTo(mApStaDisabledState);
+ }
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return HANDLED;
+ }
+ }
+
+ class EcmState extends State {
+ @Override
+ public void enter() {
+ mWifiStateMachine.setSupplicantRunning(false);
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ if (msg.what == CMD_EMERGENCY_MODE_CHANGED && msg.arg1 == 0) {
+ if (mSettingsStore.isWifiToggleEnabled()) {
+ if (mDeviceIdle == false) {
+ transitionTo(mDeviceActiveState);
+ } else {
+ checkLocksAndTransitionWhenDeviceIdle();
+ }
+ } else if (mSettingsStore.isScanAlwaysAvailable()) {
+ transitionTo(mStaDisabledWithScanState);
+ } else {
+ transitionTo(mApStaDisabledState);
+ }
+ return HANDLED;
+ } else {
+ return NOT_HANDLED;
+ }
+ }
+ }
+
+ /* Parent: StaEnabledState */
+ class DeviceActiveState extends State {
+ @Override
+ public void enter() {
+ mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
+ mWifiStateMachine.setDriverStart(true);
+ mWifiStateMachine.setHighPerfModeEnabled(false);
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ if (msg.what == CMD_DEVICE_IDLE) {
+ checkLocksAndTransitionWhenDeviceIdle();
+ // We let default state handle the rest of work
+ } else if (msg.what == CMD_USER_PRESENT) {
+ // TLS networks can't connect until user unlocks keystore. KeyStore
+ // unlocks when the user punches PIN after the reboot. So use this
+ // trigger to get those networks connected.
+ if (mFirstUserSignOnSeen == false) {
+ mWifiStateMachine.reloadTlsNetworksAndReconnect();
+ }
+ mFirstUserSignOnSeen = true;
+ return HANDLED;
+ }
+ return NOT_HANDLED;
+ }
+ }
+
+ /* Parent: StaEnabledState */
+ class DeviceInactiveState extends State {
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case CMD_LOCKS_CHANGED:
+ checkLocksAndTransitionWhenDeviceIdle();
+ updateBatteryWorkSource();
+ return HANDLED;
+ case CMD_SCREEN_ON:
+ transitionTo(mDeviceActiveState);
+ // More work in default state
+ return NOT_HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+ }
+
+ /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a scan only lock. */
+ class ScanOnlyLockHeldState extends State {
+ @Override
+ public void enter() {
+ mWifiStateMachine.setOperationalMode(WifiStateMachine.SCAN_ONLY_MODE);
+ mWifiStateMachine.setDriverStart(true);
+ }
+ }
+
+ /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a full lock. */
+ class FullLockHeldState extends State {
+ @Override
+ public void enter() {
+ mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
+ mWifiStateMachine.setDriverStart(true);
+ mWifiStateMachine.setHighPerfModeEnabled(false);
+ }
+ }
+
+ /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a high perf lock. */
+ class FullHighPerfLockHeldState extends State {
+ @Override
+ public void enter() {
+ mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
+ mWifiStateMachine.setDriverStart(true);
+ mWifiStateMachine.setHighPerfModeEnabled(true);
+ }
+ }
+
+ /* Parent: DeviceInactiveState. Device is inactive and no app is holding a wifi lock. */
+ class NoLockHeldState extends State {
+ @Override
+ public void enter() {
+ mWifiStateMachine.setDriverStart(false);
+ }
+ }
+
+ private void checkLocksAndTransitionWhenDeviceIdle() {
+ if (mLocks.hasLocks()) {
+ switch (mLocks.getStrongestLockMode()) {
+ case WIFI_MODE_FULL:
+ transitionTo(mFullLockHeldState);
+ break;
+ case WIFI_MODE_FULL_HIGH_PERF:
+ transitionTo(mFullHighPerfLockHeldState);
+ break;
+ case WIFI_MODE_SCAN_ONLY:
+ transitionTo(mScanOnlyLockHeldState);
+ break;
+ default:
+ loge("Illegal lock " + mLocks.getStrongestLockMode());
+ }
+ } else {
+ if (mSettingsStore.isScanAlwaysAvailable()) {
+ transitionTo(mScanOnlyLockHeldState);
+ } else {
+ transitionTo(mNoLockHeldState);
+ }
+ }
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ super.dump(fd, pw, args);
+
+ pw.println("mScreenOff " + mScreenOff);
+ pw.println("mDeviceIdle " + mDeviceIdle);
+ pw.println("mPluggedType " + mPluggedType);
+ pw.println("mIdleMillis " + mIdleMillis);
+ pw.println("mSleepPolicy " + mSleepPolicy);
+ }
+}