blob: a3d514e304ca9ebb758d4cf6fb4cb60e8d860964 [file] [log] [blame]
Irfan Sheriff11aefad2013-03-06 07:57:41 -08001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wifi;
18
19import android.app.AlarmManager;
20import android.app.PendingIntent;
21import android.content.BroadcastReceiver;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
25import android.database.ContentObserver;
26import android.net.ConnectivityManager;
27import android.net.NetworkInfo;
28import android.net.wifi.WifiConfiguration;
29import android.net.wifi.WifiManager;
30import static android.net.wifi.WifiManager.WIFI_MODE_FULL;
31import static android.net.wifi.WifiManager.WIFI_MODE_FULL_HIGH_PERF;
32import static android.net.wifi.WifiManager.WIFI_MODE_SCAN_ONLY;
33import android.net.wifi.WifiStateMachine;
34import android.os.Handler;
35import android.os.Looper;
36import android.os.Message;
Robert Greenwaltc12783a2013-05-16 12:48:20 -070037import android.os.SystemClock;
Irfan Sheriff11aefad2013-03-06 07:57:41 -080038import android.os.WorkSource;
39import android.provider.Settings;
40import android.util.Slog;
41
42import com.android.internal.util.Protocol;
43import com.android.internal.util.State;
44import com.android.internal.util.StateMachine;
45import com.android.server.wifi.WifiService.LockList;
46
47import java.io.FileDescriptor;
48import java.io.PrintWriter;
49
50class WifiController extends StateMachine {
51 private static final String TAG = "WifiController";
52 private static final boolean DBG = false;
53 private Context mContext;
54 private boolean mScreenOff;
55 private boolean mDeviceIdle;
56 private int mPluggedType;
57 private int mStayAwakeConditions;
58 private long mIdleMillis;
59 private int mSleepPolicy;
Vinit Deshapndea3038b22013-10-02 17:26:05 -070060 private boolean mFirstUserSignOnSeen = false;
Irfan Sheriff11aefad2013-03-06 07:57:41 -080061
62 private AlarmManager mAlarmManager;
63 private PendingIntent mIdleIntent;
64 private static final int IDLE_REQUEST = 0;
65
66 /**
67 * See {@link Settings.Global#WIFI_IDLE_MS}. This is the default value if a
68 * Settings.Global value is not present. This timeout value is chosen as
69 * the approximate point at which the battery drain caused by Wi-Fi
70 * being enabled but not active exceeds the battery drain caused by
71 * re-establishing a connection to the mobile data network.
72 */
73 private static final long DEFAULT_IDLE_MS = 15 * 60 * 1000; /* 15 minutes */
74
Robert Greenwaltc12783a2013-05-16 12:48:20 -070075 /**
76 * See {@link Settings.Global#WIFI_REENABLE_DELAY_MS}. This is the default value if a
77 * Settings.Global value is not present. This is the minimum time after wifi is disabled
78 * we'll act on an enable. Enable requests received before this delay will be deferred.
79 */
80 private static final long DEFAULT_REENABLE_DELAY_MS = 500;
81
Robert Greenwalte47d7d42013-05-20 11:49:46 -070082 // finding that delayed messages can sometimes be delivered earlier than expected
83 // probably rounding errors.. add a margin to prevent problems
84 private static final long DEFER_MARGIN_MS = 5;
85
Irfan Sheriff11aefad2013-03-06 07:57:41 -080086 NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
87
88 private static final String ACTION_DEVICE_IDLE =
89 "com.android.server.WifiManager.action.DEVICE_IDLE";
90
91 /* References to values tracked in WifiService */
92 final WifiStateMachine mWifiStateMachine;
93 final WifiSettingsStore mSettingsStore;
94 final LockList mLocks;
95
96 /**
97 * Temporary for computing UIDS that are responsible for starting WIFI.
98 * Protected by mWifiStateTracker lock.
99 */
100 private final WorkSource mTmpWorkSource = new WorkSource();
101
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700102 private long mReEnableDelayMillis;
103
Irfan Sheriff11aefad2013-03-06 07:57:41 -0800104 private static final int BASE = Protocol.BASE_WIFI_CONTROLLER;
105
106 static final int CMD_EMERGENCY_MODE_CHANGED = BASE + 1;
107 static final int CMD_SCREEN_ON = BASE + 2;
108 static final int CMD_SCREEN_OFF = BASE + 3;
109 static final int CMD_BATTERY_CHANGED = BASE + 4;
110 static final int CMD_DEVICE_IDLE = BASE + 5;
111 static final int CMD_LOCKS_CHANGED = BASE + 6;
112 static final int CMD_SCAN_ALWAYS_MODE_CHANGED = BASE + 7;
113 static final int CMD_WIFI_TOGGLED = BASE + 8;
114 static final int CMD_AIRPLANE_TOGGLED = BASE + 9;
115 static final int CMD_SET_AP = BASE + 10;
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700116 static final int CMD_DEFERRED_TOGGLE = BASE + 11;
Vinit Deshapndea3038b22013-10-02 17:26:05 -0700117 static final int CMD_USER_PRESENT = BASE + 12;
Irfan Sheriff11aefad2013-03-06 07:57:41 -0800118
119 private DefaultState mDefaultState = new DefaultState();
120 private StaEnabledState mStaEnabledState = new StaEnabledState();
121 private ApStaDisabledState mApStaDisabledState = new ApStaDisabledState();
122 private StaDisabledWithScanState mStaDisabledWithScanState = new StaDisabledWithScanState();
123 private ApEnabledState mApEnabledState = new ApEnabledState();
124 private DeviceActiveState mDeviceActiveState = new DeviceActiveState();
125 private DeviceInactiveState mDeviceInactiveState = new DeviceInactiveState();
126 private ScanOnlyLockHeldState mScanOnlyLockHeldState = new ScanOnlyLockHeldState();
127 private FullLockHeldState mFullLockHeldState = new FullLockHeldState();
128 private FullHighPerfLockHeldState mFullHighPerfLockHeldState = new FullHighPerfLockHeldState();
129 private NoLockHeldState mNoLockHeldState = new NoLockHeldState();
130 private EcmState mEcmState = new EcmState();
131
132 WifiController(Context context, WifiService service, Looper looper) {
133 super(TAG, looper);
134 mContext = context;
135 mWifiStateMachine = service.mWifiStateMachine;
136 mSettingsStore = service.mSettingsStore;
137 mLocks = service.mLocks;
138
139 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
140 Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
141 mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
142
143 addState(mDefaultState);
144 addState(mApStaDisabledState, mDefaultState);
145 addState(mStaEnabledState, mDefaultState);
146 addState(mDeviceActiveState, mStaEnabledState);
147 addState(mDeviceInactiveState, mStaEnabledState);
148 addState(mScanOnlyLockHeldState, mDeviceInactiveState);
149 addState(mFullLockHeldState, mDeviceInactiveState);
150 addState(mFullHighPerfLockHeldState, mDeviceInactiveState);
151 addState(mNoLockHeldState, mDeviceInactiveState);
152 addState(mStaDisabledWithScanState, mDefaultState);
153 addState(mApEnabledState, mDefaultState);
154 addState(mEcmState, mDefaultState);
Robert Greenwalt05caa2a2013-06-01 10:59:29 -0700155 if (mSettingsStore.isScanAlwaysAvailable()) {
156 setInitialState(mStaDisabledWithScanState);
157 } else {
158 setInitialState(mApStaDisabledState);
159 }
Robert Greenwalt02ba86f2013-05-18 11:24:22 -0700160 setLogRecSize(100);
161 setLogOnlyTransitions(false);
Irfan Sheriff11aefad2013-03-06 07:57:41 -0800162
163 IntentFilter filter = new IntentFilter();
164 filter.addAction(ACTION_DEVICE_IDLE);
165 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
166 mContext.registerReceiver(
167 new BroadcastReceiver() {
168 @Override
169 public void onReceive(Context context, Intent intent) {
170 String action = intent.getAction();
171 if (action.equals(ACTION_DEVICE_IDLE)) {
172 sendMessage(CMD_DEVICE_IDLE);
173 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
174 mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
175 WifiManager.EXTRA_NETWORK_INFO);
176 }
177 }
178 },
179 new IntentFilter(filter));
180
181 initializeAndRegisterForSettingsChange(looper);
182 }
183
184 private void initializeAndRegisterForSettingsChange(Looper looper) {
185 Handler handler = new Handler(looper);
186 readStayAwakeConditions();
187 registerForStayAwakeModeChange(handler);
188 readWifiIdleTime();
189 registerForWifiIdleTimeChange(handler);
Irfan Sheriff9f2e8312013-03-19 14:32:11 -0700190 readWifiSleepPolicy();
Irfan Sheriff11aefad2013-03-06 07:57:41 -0800191 registerForWifiSleepPolicyChange(handler);
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700192 readWifiReEnableDelay();
Irfan Sheriff11aefad2013-03-06 07:57:41 -0800193 }
194
195 private void readStayAwakeConditions() {
196 mStayAwakeConditions = Settings.Global.getInt(mContext.getContentResolver(),
197 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
198 }
199
200 private void readWifiIdleTime() {
201 mIdleMillis = Settings.Global.getLong(mContext.getContentResolver(),
202 Settings.Global.WIFI_IDLE_MS, DEFAULT_IDLE_MS);
203 }
204
205 private void readWifiSleepPolicy() {
206 mSleepPolicy = Settings.Global.getInt(mContext.getContentResolver(),
207 Settings.Global.WIFI_SLEEP_POLICY,
208 Settings.Global.WIFI_SLEEP_POLICY_NEVER);
209 }
210
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700211 private void readWifiReEnableDelay() {
212 mReEnableDelayMillis = Settings.Global.getLong(mContext.getContentResolver(),
213 Settings.Global.WIFI_REENABLE_DELAY_MS, DEFAULT_REENABLE_DELAY_MS);
214 }
215
Irfan Sheriff11aefad2013-03-06 07:57:41 -0800216 /**
217 * Observes settings changes to scan always mode.
218 */
219 private void registerForStayAwakeModeChange(Handler handler) {
220 ContentObserver contentObserver = new ContentObserver(handler) {
221 @Override
222 public void onChange(boolean selfChange) {
223 readStayAwakeConditions();
224 }
225 };
226
227 mContext.getContentResolver().registerContentObserver(
228 Settings.Global.getUriFor(Settings.Global.STAY_ON_WHILE_PLUGGED_IN),
229 false, contentObserver);
230 }
231
232 /**
233 * Observes settings changes to scan always mode.
234 */
235 private void registerForWifiIdleTimeChange(Handler handler) {
236 ContentObserver contentObserver = new ContentObserver(handler) {
237 @Override
238 public void onChange(boolean selfChange) {
239 readWifiIdleTime();
240 }
241 };
242
243 mContext.getContentResolver().registerContentObserver(
244 Settings.Global.getUriFor(Settings.Global.WIFI_IDLE_MS),
245 false, contentObserver);
246 }
247
248 /**
249 * Observes changes to wifi sleep policy
250 */
251 private void registerForWifiSleepPolicyChange(Handler handler) {
252 ContentObserver contentObserver = new ContentObserver(handler) {
253 @Override
254 public void onChange(boolean selfChange) {
255 readWifiSleepPolicy();
256 }
257 };
258 mContext.getContentResolver().registerContentObserver(
259 Settings.Global.getUriFor(Settings.Global.WIFI_SLEEP_POLICY),
260 false, contentObserver);
261 }
262
263 /**
264 * Determines whether the Wi-Fi chipset should stay awake or be put to
265 * sleep. Looks at the setting for the sleep policy and the current
266 * conditions.
267 *
268 * @see #shouldDeviceStayAwake(int)
269 */
270 private boolean shouldWifiStayAwake(int pluggedType) {
271 if (mSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER) {
272 // Never sleep
273 return true;
274 } else if ((mSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) &&
275 (pluggedType != 0)) {
276 // Never sleep while plugged, and we're plugged
277 return true;
278 } else {
279 // Default
280 return shouldDeviceStayAwake(pluggedType);
281 }
282 }
283
284 /**
285 * Determine whether the bit value corresponding to {@code pluggedType} is set in
286 * the bit string mStayAwakeConditions. This determines whether the device should
287 * stay awake based on the current plugged type.
288 *
289 * @param pluggedType the type of plug (USB, AC, or none) for which the check is
290 * being made
291 * @return {@code true} if {@code pluggedType} indicates that the device is
292 * supposed to stay awake, {@code false} otherwise.
293 */
294 private boolean shouldDeviceStayAwake(int pluggedType) {
295 return (mStayAwakeConditions & pluggedType) != 0;
296 }
297
298 private void updateBatteryWorkSource() {
299 mTmpWorkSource.clear();
300 if (mDeviceIdle) {
301 mLocks.updateWorkSource(mTmpWorkSource);
302 }
303 mWifiStateMachine.updateBatteryWorkSource(mTmpWorkSource);
304 }
305
306 class DefaultState extends State {
307 @Override
308 public boolean processMessage(Message msg) {
309 switch (msg.what) {
310 case CMD_SCREEN_ON:
311 mAlarmManager.cancel(mIdleIntent);
312 mScreenOff = false;
313 mDeviceIdle = false;
314 updateBatteryWorkSource();
315 break;
316 case CMD_SCREEN_OFF:
317 mScreenOff = true;
318 /*
319 * Set a timer to put Wi-Fi to sleep, but only if the screen is off
320 * AND the "stay on while plugged in" setting doesn't match the
321 * current power conditions (i.e, not plugged in, plugged in to USB,
322 * or plugged in to AC).
323 */
324 if (!shouldWifiStayAwake(mPluggedType)) {
325 //Delayed shutdown if wifi is connected
326 if (mNetworkInfo.getDetailedState() ==
327 NetworkInfo.DetailedState.CONNECTED) {
328 if (DBG) Slog.d(TAG, "set idle timer: " + mIdleMillis + " ms");
329 mAlarmManager.set(AlarmManager.RTC_WAKEUP,
330 System.currentTimeMillis() + mIdleMillis, mIdleIntent);
331 } else {
332 sendMessage(CMD_DEVICE_IDLE);
333 }
334 }
335 break;
336 case CMD_DEVICE_IDLE:
337 mDeviceIdle = true;
338 updateBatteryWorkSource();
339 break;
340 case CMD_BATTERY_CHANGED:
341 /*
342 * Set a timer to put Wi-Fi to sleep, but only if the screen is off
343 * AND we are transitioning from a state in which the device was supposed
344 * to stay awake to a state in which it is not supposed to stay awake.
345 * If "stay awake" state is not changing, we do nothing, to avoid resetting
346 * the already-set timer.
347 */
348 int pluggedType = msg.arg1;
349 if (DBG) Slog.d(TAG, "battery changed pluggedType: " + pluggedType);
350 if (mScreenOff && shouldWifiStayAwake(mPluggedType) &&
351 !shouldWifiStayAwake(pluggedType)) {
352 long triggerTime = System.currentTimeMillis() + mIdleMillis;
353 if (DBG) Slog.d(TAG, "set idle timer for " + mIdleMillis + "ms");
354 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
355 }
356
357 mPluggedType = pluggedType;
358 break;
359 case CMD_SET_AP:
360 case CMD_SCAN_ALWAYS_MODE_CHANGED:
361 case CMD_LOCKS_CHANGED:
362 case CMD_WIFI_TOGGLED:
363 case CMD_AIRPLANE_TOGGLED:
364 case CMD_EMERGENCY_MODE_CHANGED:
Robert Greenwalt02ba86f2013-05-18 11:24:22 -0700365 break;
Vinit Deshapndea3038b22013-10-02 17:26:05 -0700366 case CMD_USER_PRESENT:
367 mFirstUserSignOnSeen = true;
368 break;
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700369 case CMD_DEFERRED_TOGGLE:
Robert Greenwalt02ba86f2013-05-18 11:24:22 -0700370 log("DEFERRED_TOGGLE ignored due to state change");
Irfan Sheriff11aefad2013-03-06 07:57:41 -0800371 break;
372 default:
373 throw new RuntimeException("WifiController.handleMessage " + msg.what);
374 }
375 return HANDLED;
376 }
377
378 }
379
380 class ApStaDisabledState extends State {
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700381 private int mDeferredEnableSerialNumber = 0;
382 private boolean mHaveDeferredEnable = false;
383 private long mDisabledTimestamp;
384
Irfan Sheriff11aefad2013-03-06 07:57:41 -0800385 @Override
386 public void enter() {
387 mWifiStateMachine.setSupplicantRunning(false);
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700388 // Supplicant can't restart right away, so not the time we switched off
389 mDisabledTimestamp = SystemClock.elapsedRealtime();
390 mDeferredEnableSerialNumber++;
391 mHaveDeferredEnable = false;
Irfan Sheriff11aefad2013-03-06 07:57:41 -0800392 }
393 @Override
394 public boolean processMessage(Message msg) {
395 switch (msg.what) {
396 case CMD_WIFI_TOGGLED:
397 case CMD_AIRPLANE_TOGGLED:
398 if (mSettingsStore.isWifiToggleEnabled()) {
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700399 if (doDeferEnable(msg)) {
400 if (mHaveDeferredEnable) {
401 // have 2 toggles now, inc serial number an ignore both
402 mDeferredEnableSerialNumber++;
403 }
404 mHaveDeferredEnable = !mHaveDeferredEnable;
405 break;
406 }
Irfan Sheriff11aefad2013-03-06 07:57:41 -0800407 if (mDeviceIdle == false) {
408 transitionTo(mDeviceActiveState);
409 } else {
410 checkLocksAndTransitionWhenDeviceIdle();
411 }
412 }
413 break;
414 case CMD_SCAN_ALWAYS_MODE_CHANGED:
415 if (mSettingsStore.isScanAlwaysAvailable()) {
416 transitionTo(mStaDisabledWithScanState);
417 }
418 break;
419 case CMD_SET_AP:
420 if (msg.arg1 == 1) {
421 mWifiStateMachine.setHostApRunning((WifiConfiguration) msg.obj,
422 true);
423 transitionTo(mApEnabledState);
424 }
425 break;
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700426 case CMD_DEFERRED_TOGGLE:
Robert Greenwalt02ba86f2013-05-18 11:24:22 -0700427 if (msg.arg1 != mDeferredEnableSerialNumber) {
428 log("DEFERRED_TOGGLE ignored due to serial mismatch");
429 break;
430 }
431 log("DEFERRED_TOGGLE handled");
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700432 sendMessage((Message)(msg.obj));
433 break;
Irfan Sheriff11aefad2013-03-06 07:57:41 -0800434 default:
435 return NOT_HANDLED;
436 }
437 return HANDLED;
438 }
439
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700440 private boolean doDeferEnable(Message msg) {
441 long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp;
Robert Greenwalt5c11e8e2013-05-20 09:28:08 -0700442 if (delaySoFar >= mReEnableDelayMillis) {
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700443 return false;
444 }
445
Robert Greenwalt02ba86f2013-05-18 11:24:22 -0700446 log("WifiController msg " + msg + " deferred for " +
447 (mReEnableDelayMillis - delaySoFar) + "ms");
448
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700449 // need to defer this action.
450 Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE);
451 deferredMsg.obj = Message.obtain(msg);
452 deferredMsg.arg1 = ++mDeferredEnableSerialNumber;
Robert Greenwalte47d7d42013-05-20 11:49:46 -0700453 sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS);
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700454 return true;
455 }
456
Irfan Sheriff11aefad2013-03-06 07:57:41 -0800457 }
458
459 class StaEnabledState extends State {
460 @Override
461 public void enter() {
462 mWifiStateMachine.setSupplicantRunning(true);
463 }
464 @Override
465 public boolean processMessage(Message msg) {
466 switch (msg.what) {
467 case CMD_WIFI_TOGGLED:
468 if (! mSettingsStore.isWifiToggleEnabled()) {
469 if (mSettingsStore.isScanAlwaysAvailable()) {
470 transitionTo(mStaDisabledWithScanState);
471 } else {
472 transitionTo(mApStaDisabledState);
473 }
474 }
475 break;
476 case CMD_AIRPLANE_TOGGLED:
477 /* When wi-fi is turned off due to airplane,
478 * disable entirely (including scan)
479 */
480 if (! mSettingsStore.isWifiToggleEnabled()) {
481 transitionTo(mApStaDisabledState);
482 }
483 break;
484 case CMD_EMERGENCY_MODE_CHANGED:
485 if (msg.arg1 == 1) {
486 transitionTo(mEcmState);
487 break;
488 }
489 default:
490 return NOT_HANDLED;
491
492 }
493 return HANDLED;
494 }
495 }
496
497 class StaDisabledWithScanState extends State {
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700498 private int mDeferredEnableSerialNumber = 0;
499 private boolean mHaveDeferredEnable = false;
500 private long mDisabledTimestamp;
501
Irfan Sheriff11aefad2013-03-06 07:57:41 -0800502 @Override
503 public void enter() {
504 mWifiStateMachine.setSupplicantRunning(true);
505 mWifiStateMachine.setOperationalMode(WifiStateMachine.SCAN_ONLY_WITH_WIFI_OFF_MODE);
506 mWifiStateMachine.setDriverStart(true);
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700507 // Supplicant can't restart right away, so not the time we switched off
508 mDisabledTimestamp = SystemClock.elapsedRealtime();
509 mDeferredEnableSerialNumber++;
510 mHaveDeferredEnable = false;
Irfan Sheriff11aefad2013-03-06 07:57:41 -0800511 }
512
513 @Override
514 public boolean processMessage(Message msg) {
515 switch (msg.what) {
516 case CMD_WIFI_TOGGLED:
517 if (mSettingsStore.isWifiToggleEnabled()) {
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700518 if (doDeferEnable(msg)) {
519 if (mHaveDeferredEnable) {
520 // have 2 toggles now, inc serial number and ignore both
521 mDeferredEnableSerialNumber++;
522 }
523 mHaveDeferredEnable = !mHaveDeferredEnable;
524 break;
525 }
Irfan Sheriff11aefad2013-03-06 07:57:41 -0800526 if (mDeviceIdle == false) {
527 transitionTo(mDeviceActiveState);
528 } else {
529 checkLocksAndTransitionWhenDeviceIdle();
530 }
531 }
532 break;
533 case CMD_AIRPLANE_TOGGLED:
534 if (mSettingsStore.isAirplaneModeOn() &&
535 ! mSettingsStore.isWifiToggleEnabled()) {
536 transitionTo(mApStaDisabledState);
537 }
538 case CMD_SCAN_ALWAYS_MODE_CHANGED:
539 if (! mSettingsStore.isScanAlwaysAvailable()) {
540 transitionTo(mApStaDisabledState);
541 }
542 break;
543 case CMD_SET_AP:
544 // Before starting tethering, turn off supplicant for scan mode
545 if (msg.arg1 == 1) {
546 deferMessage(msg);
547 transitionTo(mApStaDisabledState);
548 }
549 break;
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700550 case CMD_DEFERRED_TOGGLE:
Robert Greenwalt02ba86f2013-05-18 11:24:22 -0700551 if (msg.arg1 != mDeferredEnableSerialNumber) {
552 log("DEFERRED_TOGGLE ignored due to serial mismatch");
553 break;
554 }
555 logd("DEFERRED_TOGGLE handled");
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700556 sendMessage((Message)(msg.obj));
557 break;
Irfan Sheriff11aefad2013-03-06 07:57:41 -0800558 default:
559 return NOT_HANDLED;
560 }
561 return HANDLED;
562 }
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700563
564 private boolean doDeferEnable(Message msg) {
565 long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp;
Robert Greenwalt5c11e8e2013-05-20 09:28:08 -0700566 if (delaySoFar >= mReEnableDelayMillis) {
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700567 return false;
568 }
Robert Greenwalt02ba86f2013-05-18 11:24:22 -0700569
570 log("WifiController msg " + msg + " deferred for " +
571 (mReEnableDelayMillis - delaySoFar) + "ms");
572
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700573 // need to defer this action.
574 Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE);
575 deferredMsg.obj = Message.obtain(msg);
576 deferredMsg.arg1 = ++mDeferredEnableSerialNumber;
Robert Greenwalte47d7d42013-05-20 11:49:46 -0700577 sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS);
Robert Greenwaltc12783a2013-05-16 12:48:20 -0700578 return true;
579 }
580
Irfan Sheriff11aefad2013-03-06 07:57:41 -0800581 }
582
583 class ApEnabledState extends State {
584 @Override
585 public boolean processMessage(Message msg) {
586 switch (msg.what) {
587 case CMD_AIRPLANE_TOGGLED:
588 if (mSettingsStore.isAirplaneModeOn()) {
589 mWifiStateMachine.setHostApRunning(null, false);
590 transitionTo(mApStaDisabledState);
591 }
592 break;
593 case CMD_SET_AP:
594 if (msg.arg1 == 0) {
595 mWifiStateMachine.setHostApRunning(null, false);
596 transitionTo(mApStaDisabledState);
597 }
598 break;
599 default:
600 return NOT_HANDLED;
601 }
602 return HANDLED;
603 }
604 }
605
606 class EcmState extends State {
607 @Override
608 public void enter() {
609 mWifiStateMachine.setSupplicantRunning(false);
610 }
611
612 @Override
613 public boolean processMessage(Message msg) {
614 if (msg.what == CMD_EMERGENCY_MODE_CHANGED && msg.arg1 == 0) {
615 if (mSettingsStore.isWifiToggleEnabled()) {
616 if (mDeviceIdle == false) {
617 transitionTo(mDeviceActiveState);
618 } else {
619 checkLocksAndTransitionWhenDeviceIdle();
620 }
621 } else if (mSettingsStore.isScanAlwaysAvailable()) {
622 transitionTo(mStaDisabledWithScanState);
623 } else {
624 transitionTo(mApStaDisabledState);
625 }
626 return HANDLED;
627 } else {
628 return NOT_HANDLED;
629 }
630 }
631 }
632
633 /* Parent: StaEnabledState */
634 class DeviceActiveState extends State {
635 @Override
636 public void enter() {
637 mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
638 mWifiStateMachine.setDriverStart(true);
639 mWifiStateMachine.setHighPerfModeEnabled(false);
640 }
641
642 @Override
643 public boolean processMessage(Message msg) {
644 if (msg.what == CMD_DEVICE_IDLE) {
645 checkLocksAndTransitionWhenDeviceIdle();
646 // We let default state handle the rest of work
Vinit Deshapndea3038b22013-10-02 17:26:05 -0700647 } else if (msg.what == CMD_USER_PRESENT) {
648 // TLS networks can't connect until user unlocks keystore. KeyStore
649 // unlocks when the user punches PIN after the reboot. So use this
650 // trigger to get those networks connected.
651 if (mFirstUserSignOnSeen == false) {
652 mWifiStateMachine.reloadTlsNetworksAndReconnect();
653 }
654 mFirstUserSignOnSeen = true;
655 return HANDLED;
Irfan Sheriff11aefad2013-03-06 07:57:41 -0800656 }
657 return NOT_HANDLED;
658 }
659 }
660
661 /* Parent: StaEnabledState */
662 class DeviceInactiveState extends State {
663 @Override
664 public boolean processMessage(Message msg) {
665 switch (msg.what) {
666 case CMD_LOCKS_CHANGED:
667 checkLocksAndTransitionWhenDeviceIdle();
668 updateBatteryWorkSource();
669 return HANDLED;
670 case CMD_SCREEN_ON:
671 transitionTo(mDeviceActiveState);
672 // More work in default state
673 return NOT_HANDLED;
674 default:
675 return NOT_HANDLED;
676 }
677 }
678 }
679
680 /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a scan only lock. */
681 class ScanOnlyLockHeldState extends State {
682 @Override
683 public void enter() {
684 mWifiStateMachine.setOperationalMode(WifiStateMachine.SCAN_ONLY_MODE);
685 mWifiStateMachine.setDriverStart(true);
686 }
687 }
688
689 /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a full lock. */
690 class FullLockHeldState extends State {
691 @Override
692 public void enter() {
693 mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
694 mWifiStateMachine.setDriverStart(true);
695 mWifiStateMachine.setHighPerfModeEnabled(false);
696 }
697 }
698
699 /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a high perf lock. */
700 class FullHighPerfLockHeldState extends State {
701 @Override
702 public void enter() {
703 mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
704 mWifiStateMachine.setDriverStart(true);
705 mWifiStateMachine.setHighPerfModeEnabled(true);
706 }
707 }
708
709 /* Parent: DeviceInactiveState. Device is inactive and no app is holding a wifi lock. */
710 class NoLockHeldState extends State {
711 @Override
712 public void enter() {
713 mWifiStateMachine.setDriverStart(false);
714 }
715 }
716
717 private void checkLocksAndTransitionWhenDeviceIdle() {
718 if (mLocks.hasLocks()) {
719 switch (mLocks.getStrongestLockMode()) {
720 case WIFI_MODE_FULL:
721 transitionTo(mFullLockHeldState);
722 break;
723 case WIFI_MODE_FULL_HIGH_PERF:
724 transitionTo(mFullHighPerfLockHeldState);
725 break;
726 case WIFI_MODE_SCAN_ONLY:
727 transitionTo(mScanOnlyLockHeldState);
728 break;
729 default:
730 loge("Illegal lock " + mLocks.getStrongestLockMode());
731 }
732 } else {
733 if (mSettingsStore.isScanAlwaysAvailable()) {
734 transitionTo(mScanOnlyLockHeldState);
735 } else {
736 transitionTo(mNoLockHeldState);
737 }
738 }
739 }
740
741 @Override
742 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
743 super.dump(fd, pw, args);
744
745 pw.println("mScreenOff " + mScreenOff);
746 pw.println("mDeviceIdle " + mDeviceIdle);
747 pw.println("mPluggedType " + mPluggedType);
748 pw.println("mIdleMillis " + mIdleMillis);
749 pw.println("mSleepPolicy " + mSleepPolicy);
750 }
751}