NetworkManager: Enable "before wifi" action support on every hasWifiToggle platform (#10669)

* Enable before_wifi_action & after_wifi_action on hasWifiToggle platforms (which is basically all of 'em except naked SDL).
* Decouple restoreWifiAsync from hasWifiManger, because we can do that on other platforms (namely, Kindle. Probably PB, too, but WiFi is already a mess there, and I can't test it).
* Implement restoreWifiAsync on Kindle.
* Properly flag rM as hasWifiManager & hasFastWifiStatusQuery, because it is actually both of those (it uses our wpa_supplicant backend).
* Update the KOSync checks to take these changes into account, to properly disable auto_sync if necessary.
* Really made the Network* event signaling consistent. For realz this time.
* In an effort to make the whole beforeWifiAction framework somewhat usable there, we now assume connectivity is always available on !hasWifiToggle platforms...
reviewable/pr10681/r1
NiLuJe 10 months ago committed by GitHub
parent 41a07a2a66
commit d57325aaf6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -32,6 +32,7 @@ local Cervantes = Generic:extend{
hasFastWifiStatusQuery = yes,
hasKeys = yes,
hasWifiManager = yes,
hasWifiRestore = yes,
canReboot = yes,
canPowerOff = yes,
canSuspend = yes,

@ -46,6 +46,7 @@ local Device = {
hasFewKeys = no,
hasWifiToggle = yes,
hasWifiManager = no,
hasWifiRestore = no,
isDefaultFullscreen = yes,
isHapticFeedbackEnabled = no,
isDeprecated = no, -- device no longer receive OTA updates
@ -278,13 +279,6 @@ function Device:onPowerEvent(ev)
else
logger.dbg("Resuming...")
UIManager:unschedule(self.suspend)
if self:hasWifiManager() then
local network_manager = require("ui/network/manager")
if network_manager.wifi_was_on and G_reader_settings:isTrue("auto_restore_wifi") then
network_manager:restoreWifiAsync()
network_manager:scheduleConnectivityCheck()
end
end
self:resume()
local widget_was_closed = Screensaver:close()
if widget_was_closed and self:needsScreenRefreshAfterResume() then
@ -313,8 +307,7 @@ function Device:onPowerEvent(ev)
if self:hasWifiToggle() then
local network_manager = require("ui/network/manager")
if network_manager:isWifiOn() then
UIManager:broadcastEvent(Event:new("NetworkDisconnecting"))
network_manager:turnOffWifi()
network_manager:disableWifi()
end
end
self:rescheduleSuspend()
@ -347,8 +340,7 @@ function Device:onPowerEvent(ev)
-- because suspend will at best fail, and at worst deadlock the system if Wi-Fi is on,
-- regardless of who enabled it!
if network_manager:isWifiOn() then
UIManager:broadcastEvent(Event:new("NetworkDisconnecting"))
network_manager:turnOffWifi()
network_manager:disableWifi()
end
end
-- Only turn off the frontlight *after* we've displayed the screensaver and dealt with Wi-Fi,

@ -138,6 +138,7 @@ local Kindle = Generic:extend{
isSpecialOffers = isSpecialOffers(),
hasOTAUpdates = yes,
hasFastWifiStatusQuery = yes,
hasWifiRestore = yes,
-- NOTE: HW inversion is generally safe on mxcfb Kindles
canHWInvert = yes,
-- NOTE: And the fb driver is generally sane on those, too
@ -186,6 +187,10 @@ function Kindle:initNetworkManager(NetworkMgr)
return "wlan0" -- so far, all Kindles appear to use wlan0
end
function NetworkMgr:restoreWifiAsync()
kindleEnableWifi(1)
end
NetworkMgr.isWifiOn = NetworkMgr.sysfsWifiOn
NetworkMgr.isConnected = NetworkMgr.ifHasAnAddress
end

@ -95,6 +95,7 @@ local Kobo = Generic:extend{
hasOTAUpdates = yes,
hasFastWifiStatusQuery = yes,
hasWifiManager = yes,
hasWifiRestore = yes,
canStandby = no, -- will get updated by checkStandby()
canReboot = yes,
canPowerOff = yes,

@ -35,6 +35,8 @@ local Remarkable = Generic:extend{
hasKeys = yes,
needsScreenRefreshAfterResume = no,
hasOTAUpdates = yes,
hasFastWifiStatusQuery = yes,
hasWifiManager = yes,
canReboot = yes,
canPowerOff = yes,
canSuspend = yes,

@ -168,10 +168,6 @@ function SonyPRSTUX:initNetworkManager(NetworkMgr)
os.execute("dhclient -x wlan0")
end
function NetworkMgr:restoreWifiAsync()
-- os.execute("./restore-wifi-async.sh")
end
--[[
function NetworkMgr:isWifiOn()
return 0 == os.execute("wmiconfig -i wlan0 --wlan query | grep -q enabled")

@ -8,7 +8,7 @@ local logger = require("logger")
local _ = require("gettext")
-- Date at which the last migration snippet was added
local CURRENT_MIGRATION_DATE = 20230707
local CURRENT_MIGRATION_DATE = 20230710
-- Retrieve the date of the previous migration, if any
local last_migration_date = G_reader_settings:readSetting("last_migration_date", 0)
@ -517,9 +517,36 @@ if last_migration_date < 20230531 then
end
end
-- 20230627, Migrate to a full settings table, and disable KOSync's auto sync mode if wifi_enable_action is not turn_on
if last_migration_date < 20230627 then
logger.info("Performing one-time migration for 20230627")
-- 20230703, FileChooser Sort by: "date modified" only
if last_migration_date < 20230703 then
logger.info("Performing one-time migration for 20230703")
local collate = G_reader_settings:readSetting("collate")
if collate == "modification" or collate == "access" or collate == "change" then
G_reader_settings:saveSetting("collate", "date")
end
end
-- 20230707, OPDS, no more special calibre catalog
if last_migration_date < 20230707 then
logger.info("Performing one-time migration for 20230707")
local calibre_opds = G_reader_settings:readSetting("calibre_opds")
if calibre_opds and calibre_opds.host and calibre_opds.port then
local opds_servers = G_reader_settings:readSetting("opds_servers") or {}
table.insert(opds_servers, 1, {
title = _("Local calibre library"),
url = string.format("http://%s:%d/opds", calibre_opds.host, calibre_opds.port),
username = calibre_opds.username,
password = calibre_opds.password,
})
G_reader_settings:saveSetting("opds_servers", opds_servers)
G_reader_settings:delSetting("calibre_opds")
end
end
-- 20230710, Migrate to a full settings table, and disable KOSync's auto sync mode if wifi_enable_action is not turn_on
if last_migration_date < 20230710 then
logger.info("Performing one-time migration for 20230710")
-- c.f., PluginLoader
local package_path = package.path
@ -549,7 +576,7 @@ if last_migration_date < 20230627 then
end
local Device = require("device")
if Device:hasWifiManager() and G_reader_settings:readSetting("wifi_enable_action") ~= "turn_on" then
if Device:hasWifiToggle() and G_reader_settings:readSetting("wifi_enable_action") ~= "turn_on" then
local kosync = G_reader_settings:readSetting("kosync")
if kosync and kosync.auto_sync then
kosync.auto_sync = false
@ -558,32 +585,5 @@ if last_migration_date < 20230627 then
end
end
-- 20230703, FileChooser Sort by: "date modified" only
if last_migration_date < 20230703 then
logger.info("Performing one-time migration for 20230703")
local collate = G_reader_settings:readSetting("collate")
if collate == "modification" or collate == "access" or collate == "change" then
G_reader_settings:saveSetting("collate", "date")
end
end
-- 20230707, OPDS, no more special calibre catalog
if last_migration_date < 20230707 then
logger.info("Performing one-time migration for 20230707")
local calibre_opds = G_reader_settings:readSetting("calibre_opds")
if calibre_opds and calibre_opds.host and calibre_opds.port then
local opds_servers = G_reader_settings:readSetting("opds_servers") or {}
table.insert(opds_servers, 1, {
title = _("Local calibre library"),
url = string.format("http://%s:%d/opds", calibre_opds.host, calibre_opds.port),
username = calibre_opds.username,
password = calibre_opds.password,
})
G_reader_settings:saveSetting("opds_servers", opds_servers)
G_reader_settings:delSetting("calibre_opds")
end
end
-- We're done, store the current migration date
G_reader_settings:saveSetting("last_migration_date", CURRENT_MIGRATION_DATE)

@ -21,6 +21,7 @@ require("ffi/posix_h")
local NetworkMgr = {
is_wifi_on = false,
is_connected = false,
pending_connectivity_check = false,
interface = nil,
}
@ -32,12 +33,12 @@ end
-- as quite a few things rely on it (KOSync, c.f. #5109; the network activity check, c.f., #6424).
function NetworkMgr:connectivityCheck(iter, callback, widget)
-- Give up after a while (restoreWifiAsync can take over 45s, so, try to cover that)...
if iter > 180 then
if iter >= 180 then
logger.info("Failed to restore Wi-Fi (after", iter * 0.25, "seconds)!")
self.wifi_was_on = false
G_reader_settings:makeFalse("wifi_was_on")
-- If we abort, murder Wi-Fi and the async script first...
if Device:hasWifiManager() then
-- If we abort, murder Wi-Fi and the async script (if any) first...
if Device:hasWifiRestore() and not Device:isKindle() then
os.execute("pkill -TERM restore-wifi-async.sh 2>/dev/null")
end
-- We were never connected to begin with, so, no disconnecting broadcast required
@ -48,6 +49,7 @@ function NetworkMgr:connectivityCheck(iter, callback, widget)
UIManager:close(widget)
UIManager:show(InfoMessage:new{ text = _("Error connecting to the network") })
end
self.pending_connectivity_check = false
return
end
@ -74,13 +76,15 @@ function NetworkMgr:connectivityCheck(iter, callback, widget)
})
end
end
self.pending_connectivity_check = false
else
UIManager:scheduleIn(0.25, self.connectivityCheck, self, iter + 1, callback, widget)
end
end
function NetworkMgr:scheduleConnectivityCheck(callback, widget)
UIManager:scheduleIn(0.5, self.connectivityCheck, self, 1, callback, widget)
self.pending_connectivity_check = true
UIManager:scheduleIn(0.25, self.connectivityCheck, self, 1, callback, widget)
end
function NetworkMgr:init()
@ -89,17 +93,16 @@ function NetworkMgr:init()
self:queryNetworkState()
self.wifi_was_on = G_reader_settings:isTrue("wifi_was_on")
if self.wifi_was_on and G_reader_settings:isTrue("auto_restore_wifi") then
-- Don't bother if WiFi is already up...
if not self.is_connected then
self:restoreWifiAsync()
end
self:scheduleConnectivityCheck()
-- Trigger an initial NetworkConnected event if WiFi was already up when we were launched
if self.is_connected then
-- NOTE: This needs to be delayed because we run on require, while NetworkListener gets spun up sliiightly later on FM/ReaderUI init...
UIManager:nextTick(UIManager.broadcastEvent, UIManager, Event:new("NetworkConnected"))
else
-- Trigger an initial NetworkConnected event if WiFi was already up when we were launched
if self.is_connected then
-- NOTE: This needs to be delayed because NetworkListener is initialized slightly later by the FM/Reader app...
UIManager:scheduleIn(2, UIManager.broadcastEvent, UIManager, Event:new("NetworkConnected"))
-- Attempt to restore wifi in the background if necessary
if Device:hasWifiRestore() and self.wifi_was_on and G_reader_settings:isTrue("auto_restore_wifi") then
logger.dbg("NetworkMgr: init will restore Wi-Fi in the background")
self:restoreWifiAsync()
self:scheduleConnectivityCheck()
end
end
@ -109,16 +112,28 @@ end
-- Following methods are Device specific which need to be initialized in
-- Device:initNetworkManager. Some of them can be set by calling
-- NetworkMgr:setWirelessBackend
function NetworkMgr:turnOnWifi() end
function NetworkMgr:turnOffWifi() end
-- This function returns status of the WiFi radio
function NetworkMgr:isWifiOn() end
function NetworkMgr:isConnected() end
function NetworkMgr:turnOnWifi(complete_callback) end
function NetworkMgr:turnOffWifi(complete_callback) end
-- This function returns the current status of the WiFi radio
-- NOTE: On !hasWifiToggle platforms, we assume networking is always available,
-- so as not to confuse the whole beforeWifiAction framework
-- (and let it fail with network errors when offline, instead of looping on unimplemented stuff...).
function NetworkMgr:isWifiOn()
if not Device:hasWifiToggle() then
return true
end
end
function NetworkMgr:isConnected()
if not Device:hasWifiToggle() then
return true
end
end
function NetworkMgr:getNetworkInterfaceName() end
function NetworkMgr:getNetworkList() end
function NetworkMgr:getCurrentNetwork() end
function NetworkMgr:authenticateNetwork() end
function NetworkMgr:disconnectNetwork() end
-- NOTE: This is currently only called on hasWifiManager platforms!
function NetworkMgr:obtainIP() end
function NetworkMgr:releaseIP() end
-- This function should call both turnOnWifi() and obtainIP() in a non-blocking manner.
@ -215,6 +230,30 @@ function NetworkMgr:ifHasAnAddress()
return ok
end
-- Wrappers around turnOnWifi & turnOffWifi with proper Event signaling
function NetworkMgr:enableWifi(wifi_cb, connectivity_cb, connectivity_widget)
-- Connecting will take a few seconds, broadcast that information so affected modules/plugins can react.
UIManager:broadcastEvent(Event:new("NetworkConnecting"))
self:turnOnWifi(wifi_cb)
-- Some turnOnWifi implementations may already have fired a connectivity check...
if not self.pending_connectivity_check then
-- This will handle sending the proper Event, manage wifi_was_on, as well as tearing down Wi-Fi in case of failures.
self:scheduleConnectivityCheck(connectivity_cb, connectivity_widget)
end
end
function NetworkMgr:disableWifi(cb)
local complete_callback = function()
UIManager:broadcastEvent(Event:new("NetworkDisconnected"))
if cb then
cb()
end
end
UIManager:broadcastEvent(Event:new("NetworkDisconnecting"))
self:turnOffWifi(complete_callback)
end
function NetworkMgr:toggleWifiOn(complete_callback, long_press)
local toggle_im = InfoMessage:new{
text = _("Turning on Wi-Fi…"),
@ -226,10 +265,7 @@ function NetworkMgr:toggleWifiOn(complete_callback, long_press)
G_reader_settings:makeTrue("wifi_was_on")
self.wifi_toggle_long_press = long_press
-- Connecting might take a few seconds (hello standby).
-- Broadcast the information, that network is changing, so affected modules/plugins can react.
UIManager:broadcastEvent(Event:new("NetworkConnecting"))
self:turnOnWifi(complete_callback)
self:enableWifi(complete_callback)
UIManager:close(toggle_im)
end
@ -244,10 +280,7 @@ function NetworkMgr:toggleWifiOff(complete_callback)
self.wifi_was_on = false
G_reader_settings:makeFalse("wifi_was_on")
-- Disconnecting might take some time, but less than connecting (hello standby).
-- Broadcast the information, that network is changing, so affected modules/plugins can react.
UIManager:broadcastEvent(Event:new("NetworkDisconnecting"))
self:turnOffWifi(complete_callback)
self:disableWifi(complete_callback)
UIManager:close(toggle_im)
end
@ -287,17 +320,26 @@ function NetworkMgr:promptWifi(complete_callback, long_press)
end
function NetworkMgr:turnOnWifiAndWaitForConnection(callback)
-- Just run the callback if WiFi is already up...
if self:isWifiOn() and self:isConnected() then
-- Given the guards in beforeWifiAction callers, this shouldn't really ever happen...
callback()
return
end
local info = InfoMessage:new{ text = _("Connecting to Wi-Fi…") }
UIManager:show(info)
UIManager:forceRePaint()
-- Don't bother if WiFi is already up...
if not (self:isWifiOn() and self:isConnected()) then
self:turnOnWifi()
-- This is a slightly tweaked variant of enableWifi, because of our peculiar connectivityCheck usage...
UIManager:broadcastEvent(Event:new("NetworkConnecting"))
self:turnOnWifi()
-- Some implementations may fire a connectivity check,
-- but we *need* our own, because of the callback & widget passing.
if self.pending_connectivity_check then
UIManager:unschedule(self.connectivityCheck)
self.pending_connectivity_check = false
end
-- This will handle sending the proper Event, manage wifi_was_on, as well as tearing down Wi-Fi in case of failures,
-- (i.e., much like getWifiToggleMenuTable).
self:scheduleConnectivityCheck(callback, info)
return info
@ -347,8 +389,7 @@ function NetworkMgr:afterWifiAction(callback)
callback()
end
elseif wifi_disable_action == "turn_off" then
UIManager:broadcastEvent(Event:new("NetworkDisconnecting"))
self:turnOffWifi(callback)
self:disableWifi(callback)
else
self:promptWifiOff(callback)
end
@ -477,12 +518,13 @@ function NetworkMgr:goOnlineToRun(callback)
local info = self:beforeWifiAction()
-- We'll basically do the same but in a blocking manner...
UIManager:unschedule(self.connectivityCheck)
self.pending_connectivity_check = false
local iter = 0
while not self.is_connected do
iter = iter + 1
if iter >= 120 then
logger.info("Failed to connect to Wi-Fi after 30s, giving up!")
logger.info("Failed to connect to Wi-Fi after", iter * 0.25, "seconds, giving up!")
self.wifi_was_on = false
G_reader_settings:makeFalse("wifi_was_on")
if info then
@ -503,6 +545,7 @@ function NetworkMgr:goOnlineToRun(callback)
-- We're finally connected!
self.wifi_was_on = true
G_reader_settings:makeTrue("wifi_was_on")
logger.info("Successfully connected to Wi-Fi (after", iter * 0.25, "seconds)!")
callback()
-- Delay this so it won't fire for dead/dying instances in case we're called by a finalizer...
UIManager:scheduleIn(2, function()
@ -529,39 +572,8 @@ function NetworkMgr:getWifiToggleMenuTable()
self:queryNetworkState()
local fully_connected = self.is_wifi_on and self.is_connected
local complete_callback = function()
-- Check the connection status again
self:queryNetworkState()
-- Notify TouchMenu to update item check state
touchmenu_instance:updateItems()
-- If Wi-Fi was on when the menu was shown, this means the tap meant to turn the Wi-Fi *off*,
-- as such, this callback will only be executed *after* the network has been disconnected.
if fully_connected then
UIManager:broadcastEvent(Event:new("NetworkDisconnected"))
else
-- On hasWifiManager devices that play with kernel modules directly,
-- double-check that the connection attempt was actually successful...
if Device:isKobo() or Device:isCervantes() then
if self.is_wifi_on and self.is_connected then
UIManager:broadcastEvent(Event:new("NetworkConnected"))
elseif self.is_wifi_on and not self.is_connected then
-- If we can't ping the gateway, despite a successful authentication w/ the AP, display a warning,
-- because this means that Wi-Fi is technically still enabled (e.g., modules are loaded).
-- We can't really enforce a turnOffWifi right now, because the user might want to try another AP or something.
-- (c.f., #5912, #4616).
-- NOTE: Keep in mind that NetworkSetting only runs this callback on *successful* connections!
-- (It's called connect_callback there).
-- This makes this branch somewhat hard to reach, which is why it gets a dedicated prompt below...
UIManager:show(InfoMessage:new{
icon = "notice-warning",
text = _("Gateway is unreachable, but Wi-Fi is still on!"),
timeout = 3,
})
end
else
-- Assume success on other platforms
UIManager:broadcastEvent(Event:new("NetworkConnected"))
end
end
end -- complete_callback()
if fully_connected then
self:toggleWifiOff(complete_callback)
@ -624,7 +636,8 @@ end
function NetworkMgr:getPowersaveMenuTable()
return {
text = _("Disable Wi-Fi connection when inactive"),
help_text = _([[This will automatically turn Wi-Fi off after a generous period of network inactivity, without disrupting workflows that require a network connection, so you can just keep reading without worrying about battery drain.]]),
help_text = Device:isKindle() and _([[This is unlikely to function properly on a stock Kindle, given how chatty the framework is.]]) or
_([[This will automatically turn Wi-Fi off after a generous period of network inactivity, without disrupting workflows that require a network connection, so you can just keep reading without worrying about battery drain.]]),
checked_func = function() return G_reader_settings:isTrue("auto_disable_wifi") end,
callback = function()
G_reader_settings:flipNilOrFalse("auto_disable_wifi")
@ -639,7 +652,7 @@ function NetworkMgr:getRestoreMenuTable()
text = _("Restore Wi-Fi connection on resume"),
help_text = _([[This will attempt to automatically and silently re-connect to Wi-Fi on startup or on resume if Wi-Fi used to be enabled the last time you used KOReader.]]),
checked_func = function() return G_reader_settings:isTrue("auto_restore_wifi") end,
enabled_func = function() return Device:hasWifiManager() end,
enabled_func = function() return Device:hasWifiRestore() end,
callback = function() G_reader_settings:flipNilOrFalse("auto_restore_wifi") end,
}
end
@ -741,9 +754,13 @@ function NetworkMgr:getMenuTable(common_settings)
common_settings.network_powersave = self:getPowersaveMenuTable()
end
if Device:hasWifiManager() or Device:isEmulator() then
if Device:hasWifiRestore() or Device:isEmulator() then
common_settings.network_restore = self:getRestoreMenuTable()
end
if Device:hasWifiManager() or Device:isEmulator() then
common_settings.network_dismiss_scan = self:getDismissScanMenuTable()
end
if Device:hasWifiToggle() then
common_settings.network_before_wifi_action = self:getBeforeWifiActionMenuTable()
common_settings.network_after_wifi_action = self:getAfterWifiActionMenuTable()
end

@ -1,6 +1,5 @@
local BD = require("ui/bidi")
local Device = require("device")
local Event = require("ui/event")
local EventListener = require("ui/widget/eventlistener")
local Font = require("ui/font")
local InfoMessage = require("ui/widget/infomessage")
@ -10,59 +9,36 @@ local logger = require("logger")
local _ = require("gettext")
local T = require("ffi/util").template
local NetworkListener = EventListener:extend{}
local NetworkListener = EventListener:extend{
-- Class members, because we want the activity check to be cross-instance...
_activity_check_scheduled = nil,
_last_tx_packets = nil,
_activity_check_delay_seconds = nil,
}
function NetworkListener:onToggleWifi()
if not NetworkMgr:isWifiOn() then
local toggle_im = InfoMessage:new{
text = _("Turning on Wi-Fi…"),
}
UIManager:show(toggle_im)
UIManager:forceRePaint()
-- NB Normal widgets should use NetworkMgr:promptWifiOn()
-- (or, better yet, the NetworkMgr:beforeWifiAction wrappers: NetworkMgr:runWhenOnline() & co.)
-- This is specifically the toggle Wi-Fi action, so consent is implied.
local complete_callback = function()
UIManager:broadcastEvent(Event:new("NetworkConnected"))
end
NetworkMgr:turnOnWifi(complete_callback)
UIManager:close(toggle_im)
else
local complete_callback = function()
UIManager:broadcastEvent(Event:new("NetworkDisconnected"))
end
local toggle_im = InfoMessage:new{
text = _("Turning off Wi-Fi…"),
}
UIManager:show(toggle_im)
UIManager:forceRePaint()
local function enableWifi()
local toggle_im = InfoMessage:new{
text = _("Turning on Wi-Fi…"),
}
UIManager:show(toggle_im)
UIManager:forceRePaint()
UIManager:broadcastEvent(Event:new("NetworkDisconnecting"))
NetworkMgr:turnOffWifi(complete_callback)
-- NB Normal widgets should use NetworkMgr:promptWifiOn()
-- (or, better yet, the NetworkMgr:beforeWifiAction wrappers: NetworkMgr:runWhenOnline() & co.)
-- This is specifically the toggle Wi-Fi action, so consent is implied.
NetworkMgr:enableWifi()
UIManager:close(toggle_im)
UIManager:show(InfoMessage:new{
text = _("Wi-Fi off."),
timeout = 1,
})
end
UIManager:close(toggle_im)
end
function NetworkListener:onInfoWifiOff()
-- That's the end goal
local complete_callback = function()
UIManager:broadcastEvent(Event:new("NetworkDisconnected"))
end
local function disableWifi()
local toggle_im = InfoMessage:new{
text = _("Turning off Wi-Fi…"),
}
UIManager:show(toggle_im)
UIManager:forceRePaint()
UIManager:broadcastEvent(Event:new("NetworkDisconnecting"))
NetworkMgr:turnOffWifi(complete_callback)
NetworkMgr:disableWifi()
UIManager:close(toggle_im)
UIManager:show(InfoMessage:new{
@ -71,23 +47,21 @@ function NetworkListener:onInfoWifiOff()
})
end
function NetworkListener:onToggleWifi()
if not NetworkMgr:isWifiOn() then
enableWifi()
else
disableWifi()
end
end
function NetworkListener:onInfoWifiOff()
disableWifi()
end
function NetworkListener:onInfoWifiOn()
if not NetworkMgr:isOnline() then
local toggle_im = InfoMessage:new{
text = _("Enabling Wi-Fi…"),
}
UIManager:show(toggle_im)
UIManager:forceRePaint()
-- NB Normal widgets should use NetworkMgr:promptWifiOn()
-- (or, better yet, the NetworkMgr:beforeWifiAction wrappers: NetworkMgr:runWhenOnline() & co.)
-- This is specifically the toggle Wi-Fi action, so consent is implied.
local complete_callback = function()
UIManager:broadcastEvent(Event:new("NetworkConnected"))
end
NetworkMgr:turnOnWifi(complete_callback)
UIManager:close(toggle_im)
enableWifi()
else
local info_text
local current_network = NetworkMgr:getCurrentNetwork()
@ -136,43 +110,40 @@ end
function NetworkListener:_unscheduleActivityCheck()
logger.dbg("NetworkListener: unschedule network activity check")
if self._activity_check_scheduled then
UIManager:unschedule(self._scheduleActivityCheck)
self._activity_check_scheduled = nil
if NetworkListener._activity_check_scheduled then
UIManager:unschedule(NetworkListener._scheduleActivityCheck)
NetworkListener._activity_check_scheduled = nil
logger.dbg("NetworkListener: network activity check unscheduled")
end
-- We also need to reset the stats, otherwise we'll be comparing apples vs. oranges... (i.e., two different network sessions)
if self._last_tx_packets then
self._last_tx_packets = nil
if NetworkListener._last_tx_packets then
NetworkListener._last_tx_packets = nil
end
if self._activity_check_delay_seconds then
self._activity_check_delay_seconds = nil
if NetworkListener._activity_check_delay_seconds then
NetworkListener._activity_check_delay_seconds = nil
end
end
-- NOTE: This must *never* access instance-specific members!
function NetworkListener:_scheduleActivityCheck()
logger.dbg("NetworkListener: network activity check")
local keep_checking = true
local tx_packets = NetworkListener:_getTxPackets()
if self._last_tx_packets and tx_packets then
if NetworkListener._last_tx_packets and tx_packets then
-- Compute noise threshold based on the current delay
local delay_seconds = self._activity_check_delay_seconds or default_network_timeout_seconds
local delay_seconds = NetworkListener._activity_check_delay_seconds or default_network_timeout_seconds
local noise_threshold = delay_seconds / default_network_timeout_seconds * network_activity_noise_margin
local delta = tx_packets - self._last_tx_packets
local delta = tx_packets - NetworkListener._last_tx_packets
-- If there was no meaningful activity (+/- a couple packets), kill the Wi-Fi
if delta <= noise_threshold then
logger.dbg("NetworkListener: No meaningful network activity (delta:", delta, "<= threshold:", noise_threshold, "[ then:", self._last_tx_packets, "vs. now:", tx_packets, "]) -> disabling Wi-Fi")
logger.dbg("NetworkListener: No meaningful network activity (delta:", delta, "<= threshold:", noise_threshold, "[ then:", NetworkListener._last_tx_packets, "vs. now:", tx_packets, "]) -> disabling Wi-Fi")
keep_checking = false
local complete_callback = function()
UIManager:broadcastEvent(Event:new("NetworkDisconnected"))
end
UIManager:broadcastEvent(Event:new("NetworkDisconnecting"))
NetworkMgr:turnOffWifi(complete_callback)
NetworkMgr:disableWifi()
-- NOTE: We leave wifi_was_on as-is on purpose, we wouldn't want to break auto_restore_wifi workflows on the next start...
else
logger.dbg("NetworkListener: Significant network activity (delta:", delta, "> threshold:", noise_threshold, "[ then:", self._last_tx_packets, "vs. now:", tx_packets, "]) -> keeping Wi-Fi enabled")
logger.dbg("NetworkListener: Significant network activity (delta:", delta, "> threshold:", noise_threshold, "[ then:", NetworkListener._last_tx_packets, "vs. now:", tx_packets, "]) -> keeping Wi-Fi enabled")
end
end
@ -182,28 +153,28 @@ function NetworkListener:_scheduleActivityCheck()
end
-- Update tracker for next iter
self._last_tx_packets = tx_packets
NetworkListener._last_tx_packets = tx_packets
-- If it's already been scheduled, increase the delay until we hit the ceiling
if self._activity_check_delay_seconds then
self._activity_check_delay_seconds = self._activity_check_delay_seconds + default_network_timeout_seconds
if NetworkListener._activity_check_delay_seconds then
NetworkListener._activity_check_delay_seconds = NetworkListener._activity_check_delay_seconds + default_network_timeout_seconds
if self._activity_check_delay_seconds > max_network_timeout_seconds then
self._activity_check_delay_seconds = max_network_timeout_seconds
if NetworkListener._activity_check_delay_seconds > max_network_timeout_seconds then
NetworkListener._activity_check_delay_seconds = max_network_timeout_seconds
end
else
self._activity_check_delay_seconds = default_network_timeout_seconds
NetworkListener._activity_check_delay_seconds = default_network_timeout_seconds
end
UIManager:scheduleIn(self._activity_check_delay_seconds, self._scheduleActivityCheck, self)
self._activity_check_scheduled = true
logger.dbg("NetworkListener: network activity check scheduled in", self._activity_check_delay_seconds, "seconds")
UIManager:scheduleIn(NetworkListener._activity_check_delay_seconds, NetworkListener._scheduleActivityCheck)
NetworkListener._activity_check_scheduled = true
logger.dbg("NetworkListener: network activity check scheduled in", NetworkListener._activity_check_delay_seconds, "seconds")
end
function NetworkListener:onNetworkConnected()
logger.dbg("NetworkListener: onNetworkConnected")
if Device:hasWifiManager() then
-- This is for the sake of events that don't emanate from NetworkMgr itself...
if Device:hasWifiToggle() then
-- This is for the sake of events that don't emanate from NetworkMgr itself (e.g., the Emu)...
NetworkMgr:setWifiState(true)
NetworkMgr:setConnectionState(true)
end
@ -214,30 +185,45 @@ function NetworkListener:onNetworkConnected()
-- If the activity check has already been scheduled for some reason, unschedule it first.
NetworkListener:_unscheduleActivityCheck()
NetworkListener:_scheduleActivityCheck()
end
function NetworkListener:onNetworkDisconnected()
logger.dbg("NetworkListener: onNetworkDisconnected")
if Device:hasWifiManager() then
if Device:hasWifiToggle() then
NetworkMgr:setWifiState(false)
NetworkMgr:setConnectionState(false)
end
if not G_reader_settings:isTrue("auto_disable_wifi") then
return
end
NetworkListener:_unscheduleActivityCheck()
-- Reset NetworkMgr's beforeWifiAction marker
NetworkMgr:clearBeforeActionFlag()
end
-- Also unschedule on suspend (and we happen to also kill Wi-Fi to do so, so resetting the stats is also relevant here)
function NetworkListener:onSuspend()
self:onNetworkDisconnected()
logger.dbg("NetworkListener: onSuspend")
-- If we haven't already (e.g., via Generic's onPowerEvent), kill Wi-Fi.
-- Except on Android, where turnOnWifi/turnOffWifi are *interactive*... :/
if Device:hasWifiToggle() and NetworkMgr:isWifiOn() and not Device:isAndroid() then
NetworkMgr:disableWifi()
end
-- Wi-Fi will be down, unschedule unconditionally
NetworkListener:_unscheduleActivityCheck()
NetworkMgr:clearBeforeActionFlag()
end
-- If the platform implements NetworkMgr:restoreWifiAsync, run it as needed
if Device:hasWifiRestore() then
function NetworkListener:onResume()
if NetworkMgr.wifi_was_on and G_reader_settings:isTrue("auto_restore_wifi") then
logger.dbg("NetworkListener: onResume will restore Wi-Fi in the background")
NetworkMgr:restoreWifiAsync()
NetworkMgr:scheduleConnectivityCheck()
end
end
end
function NetworkListener:onShowNetworkInfo()

@ -673,7 +673,7 @@ function AutoSuspend:onNetworkConnecting()
end
function AutoSuspend:onNetworkDisconnected()
logger.dbg("AutoSuspend: onNetworkDisonnected")
logger.dbg("AutoSuspend: onNetworkDisconnected")
self:_unschedule_standby()
-- Schedule the next check as usual.
self:_start_standby()

@ -56,8 +56,8 @@ KOSync.default_settings = {
custom_server = nil,
username = nil,
userkey = nil,
-- Do *not* default to auto-sync on devices w/ NetworkManager support, as wifi is unlikely to be on at all times there, and the nagging enabling this may cause requires careful consideration.
auto_sync = not Device:hasWifiManager(),
-- Do *not* default to auto-sync, as wifi may not be on at all times, and the nagging enabling this may cause requires careful consideration.
auto_sync = false,
pages_before_update = nil,
sync_forward = SYNC_STRATEGY.PROMPT,
sync_backward = SYNC_STRATEGY.DISABLE,
@ -84,7 +84,7 @@ function KOSync:init()
self.device_id = G_reader_settings:readSetting("device_id")
-- Disable auto-sync if beforeWifiAction was reset to "prompt" behind our back...
if self.settings.auto_sync and Device:hasWifiManager() and G_reader_settings:readSetting("wifi_enable_action") ~= "turn_on" then
if self.settings.auto_sync and Device:hasWifiToggle() and G_reader_settings:readSetting("wifi_enable_action") ~= "turn_on" then
self.settings.auto_sync = false
logger.warn("KOSync: Automatic sync has been disabled because wifi_enable_action is *not* turn_on")
end
@ -229,7 +229,7 @@ function KOSync:addToMainMenu(menu_items)
help_text = _([[This may lead to nagging about toggling WiFi on document close and suspend/resume, depending on the device's connectivity.]]),
callback = function()
-- Actively recommend switching the before wifi action to "turn_on" instead of prompt, as prompt will just not be practical (or even plain usable) here.
if Device:hasWifiManager() and G_reader_settings:readSetting("wifi_enable_action") ~= "turn_on" then
if Device:hasWifiToggle() and G_reader_settings:readSetting("wifi_enable_action") ~= "turn_on" then
UIManager:show(InfoMessage:new{ text = _("You will have to switch the 'Action when Wi-Fi is off' Network setting to 'turn on' to be able to enable this feature!") })
return
end
@ -868,7 +868,7 @@ function KOSync:_onResume()
logger.dbg("KOSync: onResume")
-- If we have auto_restore_wifi enabled, skip this to prevent both the "Connecting..." UI to pop-up,
-- *and* a duplicate NetworkConnected event from firing...
if Device:hasWifiManager() and NetworkMgr.wifi_was_on and G_reader_settings:isTrue("auto_restore_wifi") then
if Device:hasWifiRestore() and NetworkMgr.wifi_was_on and G_reader_settings:isTrue("auto_restore_wifi") then
return
end

@ -46,6 +46,9 @@ describe("network_manager module", function()
self:obtainIP()
end
end
function Device:hasWifiRestore()
return true
end
end)
it("should restore wifi in init if wifi was on", function()
@ -72,6 +75,7 @@ describe("network_manager module", function()
teardown(function()
function Device:initNetworkManager() end
function Device:hasWifiRestore() return false end
package.loaded["ui/network/manager"] = nil
end)
end)

Loading…
Cancel
Save