Add min delay between disable and enable of wifi

We sometimes have issues if disable, enable seq happens to fast.
This should only slow down those fast cases.

bug:8715336
Change-Id: I4f7fe9708b7c3c2300c441511838e8a70eaad5d1
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2725f6a..f742385 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4916,6 +4916,12 @@
        public static final String WIFI_P2P_DEVICE_NAME = "wifi_p2p_device_name";
 
        /**
+        * The min time between wifi disable and wifi enable
+        * @hide
+        */
+       public static final String WIFI_REENABLE_DELAY_MS = "wifi_reenable_delay";
+
+       /**
         * The number of milliseconds to delay when checking for data stalls during
         * non-aggressive detection. (screen is turned off.)
         * @hide
diff --git a/services/java/com/android/server/wifi/WifiController.java b/services/java/com/android/server/wifi/WifiController.java
index 6e6b8cc..52aaac7 100644
--- a/services/java/com/android/server/wifi/WifiController.java
+++ b/services/java/com/android/server/wifi/WifiController.java
@@ -34,6 +34,7 @@
 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;
@@ -70,6 +71,13 @@
      */
     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;
+
     NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
 
     private static final String ACTION_DEVICE_IDLE =
@@ -86,6 +94,8 @@
      */
     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;
@@ -98,6 +108,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;
 
     private DefaultState mDefaultState = new DefaultState();
     private StaEnabledState mStaEnabledState = new StaEnabledState();
@@ -168,6 +179,7 @@
         registerForWifiIdleTimeChange(handler);
         readWifiSleepPolicy();
         registerForWifiSleepPolicyChange(handler);
+        readWifiReEnableDelay();
     }
 
     private void readStayAwakeConditions() {
@@ -186,6 +198,11 @@
                 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.
      */
@@ -335,6 +352,7 @@
                 case CMD_WIFI_TOGGLED:
                 case CMD_AIRPLANE_TOGGLED:
                 case CMD_EMERGENCY_MODE_CHANGED:
+                case CMD_DEFERRED_TOGGLE:
                     break;
                 default:
                     throw new RuntimeException("WifiController.handleMessage " + msg.what);
@@ -345,9 +363,17 @@
     }
 
     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) {
@@ -355,6 +381,14 @@
                 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 {
@@ -374,12 +408,30 @@
                         transitionTo(mApEnabledState);
                     }
                     break;
+                case CMD_DEFERRED_TOGGLE:
+                    if (msg.arg1 != mDeferredEnableSerialNumber) break;
+                    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;
+            }
+
+            // need to defer this action.
+            Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE);
+            deferredMsg.obj = Message.obtain(msg);
+            deferredMsg.arg1 = ++mDeferredEnableSerialNumber;
+            sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar);
+            return true;
+        }
+
     }
 
     class StaEnabledState extends State {
@@ -421,11 +473,19 @@
     }
 
     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
@@ -433,6 +493,14 @@
             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 {
@@ -457,11 +525,29 @@
                         transitionTo(mApStaDisabledState);
                     }
                     break;
+                case CMD_DEFERRED_TOGGLE:
+                    if (msg.arg1 != mDeferredEnableSerialNumber) break;
+                    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;
+            }
+            // need to defer this action.
+            Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE);
+            deferredMsg.obj = Message.obtain(msg);
+            deferredMsg.arg1 = ++mDeferredEnableSerialNumber;
+            sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar);
+            return true;
+        }
+
     }
 
     class ApEnabledState extends State {