From 52e4b23e34348eb78e832a46c4f9fea67a1e3bf9 Mon Sep 17 00:00:00 2001 From: d34d Date: Fri, 29 Jan 2016 11:44:41 -0800 Subject: Tethering: Turn off Wi-Fi Hotspot after inactivity (1/3) Turn off the Wi-Fi hotspot after a specified time of inactivity. The hotspot is considered to be inactive when no clients are connected to it. Change-Id: Ife48d5254b06b4e80841d5970984ab9979574e07 --- .../com/android/server/connectivity/Tethering.java | 50 ++++++++++++++++++++++ wifi/java/android/net/wifi/WifiConfiguration.java | 10 +++++ 2 files changed, 60 insertions(+) diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index b9bbd8c..3472db2 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -36,8 +36,11 @@ import android.net.Network; import android.net.NetworkInfo; import android.net.NetworkUtils; import android.net.RouteInfo; +import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiDevice; +import android.net.wifi.WifiManager; import android.os.Binder; +import android.os.Handler; import android.os.INetworkManagementService; import android.os.Looper; import android.os.Message; @@ -164,12 +167,16 @@ public class Tethering extends BaseNetworkObserver { private static final int DNSMASQ_POLLING_INTERVAL = 1000; private static final int DNSMASQ_POLLING_MAX_TIMES = 10; + private long mWiFiApInactivityTimeout; + private final Handler mHandler; + public Tethering(Context context, INetworkManagementService nmService, INetworkStatsService statsService, Looper looper) { mContext = context; mNMService = nmService; mStatsService = statsService; mLooper = looper; + mHandler = new Handler(mLooper); mPublicSync = new Object(); @@ -269,6 +276,18 @@ public class Tethering extends BaseNetworkObserver { sm = new TetherInterfaceSM(iface, mLooper, usb); mIfaces.put(iface, sm); sm.start(); + if (isWifi(iface)) { + // check if the user has specified an inactivity timeout for wifi AP and + // if so schedule the timeout + final WifiManager wm = + (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + final WifiConfiguration apConfig = wm.getWifiApConfiguration(); + mWiFiApInactivityTimeout = + apConfig != null ? apConfig.wifiApInactivityTimeout : 0; + if (mWiFiApInactivityTimeout > 0 && mL2ConnectedDeviceMap.size() == 0) { + scheduleInactivityTimeout(); + } + } } } else { if (isUsb(iface)) { @@ -278,6 +297,9 @@ public class Tethering extends BaseNetworkObserver { } else if (sm != null) { sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN); mIfaces.remove(iface); + if (isWifi(iface)) { + cancelInactivityTimeout(); + } } } } @@ -428,6 +450,29 @@ public class Tethering extends BaseNetworkObserver { return result; } + private final Runnable mDisableWifiApRunnable = new Runnable() { + @Override + public void run() { + if (VDBG) Log.d(TAG, "Turning off hotpost due to inactivity"); + final WifiManager wifiManager = + (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + wifiManager.setWifiApEnabled(null, false); + } + }; + + private void scheduleInactivityTimeout() { + if (mWiFiApInactivityTimeout > 0) { + if (VDBG) Log.d(TAG, "scheduleInactivityTimeout: " + mWiFiApInactivityTimeout); + mHandler.removeCallbacks(mDisableWifiApRunnable); + mHandler.postDelayed(mDisableWifiApRunnable, mWiFiApInactivityTimeout); + } + } + + private void cancelInactivityTimeout() { + if (VDBG) Log.d(TAG, "cancelInactivityTimeout"); + mHandler.removeCallbacks(mDisableWifiApRunnable); + } + /* * DnsmasqThread is used to read the Device info from dnsmasq. */ @@ -511,10 +556,15 @@ public class Tethering extends BaseNetworkObserver { new DnsmasqThread(this, device, DNSMASQ_POLLING_INTERVAL, DNSMASQ_POLLING_MAX_TIMES).start(); } + cancelInactivityTimeout(); } else if (device.deviceState == WifiDevice.DISCONNECTED) { mL2ConnectedDeviceMap.remove(device.deviceAddress); mConnectedDeviceMap.remove(device.deviceAddress); sendTetherConnectStateChangedBroadcast(); + // schedule inactivity timeout if non-zero and no more devices are connected + if (mWiFiApInactivityTimeout > 0 && mL2ConnectedDeviceMap.size() == 0) { + scheduleInactivityTimeout(); + } } } catch (IllegalArgumentException ex) { Log.e(TAG, "WifiDevice IllegalArgument: " + ex); diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 9d4f6e2..35d6d9e 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -456,6 +456,13 @@ public class WifiConfiguration implements Parcelable { */ public int userApproved = USER_UNSPECIFIED; + /** + * @hide + * Inactivity time before wifi tethering is disabled. Here inactivity means no clients + * connected. A value of 0 means the AP will not be disabled when there is no activity + */ + public long wifiApInactivityTimeout; + /** The Below RSSI thresholds are used to configure AutoJoin * - GOOD/LOW/BAD thresholds are used so as to calculate link score * - UNWANTED_SOFT are used by the blacklisting logic so as to handle @@ -1556,6 +1563,7 @@ public class WifiConfiguration implements Parcelable { creationTime = source.creationTime; updateTime = source.updateTime; SIMNum = source.SIMNum; + wifiApInactivityTimeout = source.wifiApInactivityTimeout; } } @@ -1638,6 +1646,7 @@ public class WifiConfiguration implements Parcelable { dest.writeInt(numNoInternetAccessReports); dest.writeInt(noInternetAccessExpected ? 1 : 0); dest.writeInt(SIMNum); + dest.writeLong(wifiApInactivityTimeout); } /** Implement the Parcelable interface {@hide} */ @@ -1717,6 +1726,7 @@ public class WifiConfiguration implements Parcelable { config.numNoInternetAccessReports = in.readInt(); config.noInternetAccessExpected = in.readInt() != 0; config.SIMNum = in.readInt(); + config.wifiApInactivityTimeout = in.readLong(); return config; } -- cgit v1.1