Various Wi-Fi QoL improvements (#6424)

* Revamped most actions that require an internet connection to a new/fixed backend that allows forwarding the initial action and running it automatically once connected. (i.e., it'll allow you to set "Action when Wi-Fi is off" to "turn_on", and whatch stuff connect and do what you wanted automatically without having to re-click anywhere instead of showing you a Wi-Fi prompt and then not doing anything without any other feedback).
* Speaking of, fixed the "turn_on" beforeWifi action to, well, actually work. It's no longer marked as experimental.
* Consistently use "Wi-Fi" everywhere.
* On Kobo/Cervantes/Sony, implemented a "Kill Wi-Fi connection when inactive" system that will automatically disconnect from Wi-Fi after sustained *network* inactivity (i.e., you can keep reading, it'll eventually turn off on its own). This should be smart and flexible enough not to murder Wi-Fi while you need it, while still not keeping it uselessly on and murdering your battery.
(i.e., enable that + turn Wi-Fi on when off and enjoy never having to bother about Wi-Fi ever again).
* Made sending `NetworkConnected` / `NetworkDisconnected` events consistent (they were only being sent... sometimes, which made relying on 'em somewhat problematic).
* restoreWifiAsync is now only run when really needed (i.e., we no longer stomp on an existing working connection just for the hell of it).
* We no longer attempt to kill a bogus non-existent Wi-Fi connection when going to suspend, we only do it when it's actually needed.
* Every method of enabling Wi-Fi will now properly tear down Wi-Fi on failure, instead of leaving it in an undefined state.
* Fixed an issue in the fancy crash screen on Kobo/reMarkable that could sometime lead to the log excerpt being missing.
* Worked-around a number of sneaky issues related to low-level Wi-Fi/DHCP/DNS handling on Kobo (see the lengthy comments [below](https://github.com/koreader/koreader/pull/6424#issuecomment-663881059) for details). Fix #6421 
Incidentally, this should also fix the inconsistencies experienced re: Wi-Fi behavior in Nickel when toggling between KOReader and Nickel (use NM/KFMon, and run a current FW for best results).
* For developers, this involves various cleanups around NetworkMgr and NetworkListener. Documentation is in-line, above the concerned functions.
reviewable/pr6438/r1
NiLuJe 4 years ago committed by GitHub
parent e23f68e5f7
commit 37a01100b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -149,20 +149,17 @@ function CloudStorage:openCloudServer(url)
local tbl local tbl
local NetworkMgr = require("ui/network/manager") local NetworkMgr = require("ui/network/manager")
if self.type == "dropbox" then if self.type == "dropbox" then
if not NetworkMgr:isOnline() then if NetworkMgr:willRerunWhenOnline(function() self:openCloudServer(url) end) then
NetworkMgr:promptWifiOn()
return return
end end
tbl = DropBox:run(url, self.password, self.choose_folder_mode) tbl = DropBox:run(url, self.password, self.choose_folder_mode)
elseif self.type == "ftp" then elseif self.type == "ftp" then
if not NetworkMgr:isConnected() then if NetworkMgr:willRerunWhenConnected(function() self:openCloudServer(url) end) then
NetworkMgr:promptWifiOn()
return return
end end
tbl = Ftp:run(self.address, self.username, self.password, url) tbl = Ftp:run(self.address, self.username, self.password, url)
elseif self.type == "webdav" then elseif self.type == "webdav" then
if not NetworkMgr:isConnected() then if NetworkMgr:willRerunWhenConnected(function() self:openCloudServer(url) end) then
NetworkMgr:promptWifiOn()
return return
end end
tbl = WebDav:run(self.address, self.username, self.password, url) tbl = WebDav:run(self.address, self.username, self.password, url)

@ -836,11 +836,10 @@ function ReaderDictionary:showDownload(downloadable_dicts)
for dummy, dict in ipairs(downloadable_dicts) do for dummy, dict in ipairs(downloadable_dicts) do
table.insert(kv_pairs, {dict.name, "", table.insert(kv_pairs, {dict.name, "",
callback = function() callback = function()
if not NetworkMgr:isOnline() then local connect_callback = function()
NetworkMgr:promptWifiOn() self:downloadDictionaryPrep(dict)
return
end end
self:downloadDictionaryPrep(dict) NetworkMgr:runWhenOnline(connect_callback)
end}) end})
local lang local lang
if dict.lang_in == dict.lang_out then if dict.lang_in == dict.lang_out then

@ -57,7 +57,7 @@ local symbol_prefix = {
frontlight = C_("FooterLetterPrefix", "L:"), frontlight = C_("FooterLetterPrefix", "L:"),
-- @translators This is the footer letter prefix for memory usage. -- @translators This is the footer letter prefix for memory usage.
mem_usage = C_("FooterLetterPrefix", "M:"), mem_usage = C_("FooterLetterPrefix", "M:"),
-- @translators This is the footer letter prefix for wifi status. -- @translators This is the footer letter prefix for Wi-Fi status.
wifi_status = C_("FooterLetterPrefix", "W:"), wifi_status = C_("FooterLetterPrefix", "W:"),
}, },
icons = { icons = {
@ -1835,7 +1835,7 @@ function ReaderFooter:applyFooterMode(mode)
-- 7 for from statistics chapter time to read -- 7 for from statistics chapter time to read
-- 8 for front light level -- 8 for front light level
-- 9 for memory usage -- 9 for memory usage
-- 10 for wifi status -- 10 for Wi-Fi status
-- 11 for book title -- 11 for book title
-- 12 for current chapter -- 12 for current chapter

@ -384,10 +384,11 @@ function ReaderWikipedia:onLookupWikipedia(word, box, get_fullpage, forced_lang)
end end
function ReaderWikipedia:lookupWikipedia(word, box, get_fullpage, forced_lang) function ReaderWikipedia:lookupWikipedia(word, box, get_fullpage, forced_lang)
if not NetworkMgr:isOnline() then if NetworkMgr:willRerunWhenOnline(function() self:lookupWikipedia(word, box, get_fullpage, forced_lang) end) then
NetworkMgr:promptWifiOn() -- Not online yet, nothing more to do here, NetworkMgr will forward the callback and run it once connected!
return return
end end
-- word is the text to query. If get_fullpage is true, it is the -- word is the text to query. If get_fullpage is true, it is the
-- exact wikipedia page title we want the full page of. -- exact wikipedia page title we want the full page of.
self:initLanguages(word) self:initLanguages(word)
@ -525,11 +526,10 @@ function ReaderWikipedia:onSaveSettings()
end end
function ReaderWikipedia:onShowWikipediaLookup() function ReaderWikipedia:onShowWikipediaLookup()
if NetworkMgr:isOnline() then local connect_callback = function()
self:lookupInput() self:lookupInput()
else
NetworkMgr:promptWifiOn()
end end
NetworkMgr:runWhenOnline(connect_callback)
return true return true
end end

@ -17,7 +17,7 @@ local function isConnected()
-- read carrier state from sysfs (for eth0) -- read carrier state from sysfs (for eth0)
local file = io.open("/sys/class/net/eth0/carrier", "rb") local file = io.open("/sys/class/net/eth0/carrier", "rb")
-- file exists while wifi module is loaded. -- file exists while Wi-Fi module is loaded.
if not file then return 0 end if not file then return 0 end
-- 0 means not connected, 1 connected -- 0 means not connected, 1 connected
@ -224,7 +224,7 @@ end
-- wireless -- wireless
function Cervantes:initNetworkManager(NetworkMgr) function Cervantes:initNetworkManager(NetworkMgr)
function NetworkMgr:turnOffWifi(complete_callback) function NetworkMgr:turnOffWifi(complete_callback)
logger.info("Cervantes: disabling WiFi") logger.info("Cervantes: disabling Wi-Fi")
self:releaseIP() self:releaseIP()
os.execute("./disable-wifi.sh") os.execute("./disable-wifi.sh")
if complete_callback then if complete_callback then
@ -232,10 +232,13 @@ function Cervantes:initNetworkManager(NetworkMgr)
end end
end end
function NetworkMgr:turnOnWifi(complete_callback) function NetworkMgr:turnOnWifi(complete_callback)
logger.info("Cervantes: enabling WiFi") logger.info("Cervantes: enabling Wi-Fi")
os.execute("./enable-wifi.sh") os.execute("./enable-wifi.sh")
self:reconnectOrShowNetworkMenu(complete_callback) self:reconnectOrShowNetworkMenu(complete_callback)
end end
function NetworkMgr:getNetworkInterfaceName()
return "eth0"
end
NetworkMgr:setWirelessBackend("wpa_supplicant", {ctrl_interface = "/var/run/wpa_supplicant/eth0"}) NetworkMgr:setWirelessBackend("wpa_supplicant", {ctrl_interface = "/var/run/wpa_supplicant/eth0"})
function NetworkMgr:obtainIP() function NetworkMgr:obtainIP()
os.execute("./obtain-ip.sh") os.execute("./obtain-ip.sh")

@ -282,12 +282,12 @@ function Device:onPowerEvent(ev)
self.screen_saver_mode = true self.screen_saver_mode = true
UIManager:scheduleIn(0.1, function() UIManager:scheduleIn(0.1, function()
local network_manager = require("ui/network/manager") local network_manager = require("ui/network/manager")
-- NOTE: wifi_was_on does not necessarily mean that WiFi is *currently* on! It means *we* enabled it. -- NOTE: wifi_was_on does not necessarily mean that Wi-Fi is *currently* on! It means *we* enabled it.
-- This is critical on Kobos (c.f., #3936), where it might still be on from KSM or Nickel, -- This is critical on Kobos (c.f., #3936), where it might still be on from KSM or Nickel,
-- without us being aware of it (i.e., wifi_was_on still unset or false), -- without us being aware of it (i.e., wifi_was_on still unset or false),
-- because suspend will at best fail, and at worst deadlock the system if WiFi is on, -- because suspend will at best fail, and at worst deadlock the system if Wi-Fi is on,
-- regardless of who enabled it! -- regardless of who enabled it!
if network_manager.wifi_was_on or network_manager:isWifiOn() then if network_manager:isWifiOn() then
network_manager:releaseIP() network_manager:releaseIP()
network_manager:turnOffWifi() network_manager:turnOffWifi()
end end

@ -12,7 +12,7 @@ local function kindleEnableWifi(toggle)
end end
if lipc_handle then if lipc_handle then
-- Be extremely thorough... c.f., #6019 -- Be extremely thorough... c.f., #6019
-- NOTE: I *assume* this'll also ensure we prefer WiFi over 3G/4G, which is a plus in my book... -- NOTE: I *assume* this'll also ensure we prefer Wi-Fi over 3G/4G, which is a plus in my book...
if toggle == 1 then if toggle == 1 then
lipc_handle:set_int_property("com.lab126.cmd", "wirelessEnable", 1) lipc_handle:set_int_property("com.lab126.cmd", "wirelessEnable", 1)
lipc_handle:set_int_property("com.lab126.wifid", "enable", 1) lipc_handle:set_int_property("com.lab126.wifid", "enable", 1)
@ -103,20 +103,19 @@ function Kindle:initNetworkManager(NetworkMgr)
function NetworkMgr:turnOnWifi(complete_callback) function NetworkMgr:turnOnWifi(complete_callback)
kindleEnableWifi(1) kindleEnableWifi(1)
-- NOTE: As we defer the actual work to lipc, -- NOTE: As we defer the actual work to lipc,
-- we have no guarantee the WiFi state will have changed by the time kindleEnableWifi returns, -- we have no guarantee the Wi-Fi state will have changed by the time kindleEnableWifi returns,
-- so, delay the callback a bit... -- so, delay the callback until we at least can ensure isConnect is true.
if complete_callback then if complete_callback then
local UIManager = require("ui/uimanager") NetworkMgr:scheduleConnectivityCheck(complete_callback)
UIManager:scheduleIn(1, complete_callback)
end end
end end
function NetworkMgr:turnOffWifi(complete_callback) function NetworkMgr:turnOffWifi(complete_callback)
kindleEnableWifi(0) kindleEnableWifi(0)
-- NOTE: Same here... -- NOTE: Same here, except disconnect is simpler, so a dumb delay will do...
if complete_callback then if complete_callback then
local UIManager = require("ui/uimanager") local UIManager = require("ui/uimanager")
UIManager:scheduleIn(1, complete_callback) UIManager:scheduleIn(2, complete_callback)
end end
end end
@ -374,7 +373,7 @@ local KindleOasis = Kindle:new{
hasGSensor = yes, hasGSensor = yes,
display_dpi = 300, display_dpi = 300,
--[[ --[[
-- NOTE: Points to event3 on WiFi devices, event4 on 3G devices... -- NOTE: Points to event3 on Wi-Fi devices, event4 on 3G devices...
-- 3G devices apparently have an extra SX9500 Proximity/Capacitive controller for mysterious purposes... -- 3G devices apparently have an extra SX9500 Proximity/Capacitive controller for mysterious purposes...
-- This evidently screws with the ordering, so, use the udev by-path path instead to avoid hackier workarounds. -- This evidently screws with the ordering, so, use the udev by-path path instead to avoid hackier workarounds.
-- cf. #2181 -- cf. #2181
@ -405,7 +404,7 @@ local KindlePaperWhite4 = Kindle:new{
display_dpi = 300, display_dpi = 300,
-- NOTE: LTE devices once again have a mysterious extra SX9310 proximity sensor... -- NOTE: LTE devices once again have a mysterious extra SX9310 proximity sensor...
-- Except this time, we can't rely on by-path, because there's no entry for the TS :/. -- Except this time, we can't rely on by-path, because there's no entry for the TS :/.
-- Should be event2 on WiFi, event3 on LTE, we'll fix it in init. -- Should be event2 on Wi-Fi, event3 on LTE, we'll fix it in init.
touch_dev = "/dev/input/event2", touch_dev = "/dev/input/event2",
} }

@ -10,11 +10,11 @@ local function yes() return true end
local function no() return false end local function no() return false end
local function koboEnableWifi(toggle) local function koboEnableWifi(toggle)
if toggle == 1 then if toggle == true then
logger.info("Kobo WiFi: enabling WiFi") logger.info("Kobo Wi-Fi: enabling Wi-Fi")
os.execute("./enable-wifi.sh") os.execute("./enable-wifi.sh")
else else
logger.info("Kobo WiFi: disabling WiFi") logger.info("Kobo Wi-Fi: disabling Wi-Fi")
os.execute("./disable-wifi.sh") os.execute("./disable-wifi.sh")
end end
end end
@ -414,14 +414,15 @@ end
function Kobo:initNetworkManager(NetworkMgr) function Kobo:initNetworkManager(NetworkMgr)
function NetworkMgr:turnOffWifi(complete_callback) function NetworkMgr:turnOffWifi(complete_callback)
koboEnableWifi(0) self:releaseIP()
koboEnableWifi(false)
if complete_callback then if complete_callback then
complete_callback() complete_callback()
end end
end end
function NetworkMgr:turnOnWifi(complete_callback) function NetworkMgr:turnOnWifi(complete_callback)
koboEnableWifi(1) koboEnableWifi(true)
self:showNetworkMenu(complete_callback) self:showNetworkMenu(complete_callback)
end end
@ -429,6 +430,9 @@ function Kobo:initNetworkManager(NetworkMgr)
if not net_if then if not net_if then
net_if = "eth0" net_if = "eth0"
end end
function NetworkMgr:getNetworkInterfaceName()
return net_if
end
NetworkMgr:setWirelessBackend( NetworkMgr:setWirelessBackend(
"wpa_supplicant", {ctrl_interface = "/var/run/wpa_supplicant/" .. net_if}) "wpa_supplicant", {ctrl_interface = "/var/run/wpa_supplicant/" .. net_if})
@ -444,14 +448,14 @@ function Kobo:initNetworkManager(NetworkMgr)
os.execute("./restore-wifi-async.sh") os.execute("./restore-wifi-async.sh")
end end
-- NOTE: Cheap-ass way of checking if WiFi seems to be enabled... -- NOTE: Cheap-ass way of checking if Wi-Fi seems to be enabled...
-- Since the crux of the issues lies in race-y module unloading, this is perfectly fine for our usage. -- Since the crux of the issues lies in race-y module unloading, this is perfectly fine for our usage.
function NetworkMgr:isWifiOn() function NetworkMgr:isWifiOn()
local fd = io.open("/proc/modules", "r") local fd = io.open("/proc/modules", "r")
if fd then if fd then
local lsmod = fd:read("*all") local lsmod = fd:read("*all")
fd:close() fd:close()
-- lsmod is usually empty, unless WiFi or USB is enabled -- lsmod is usually empty, unless Wi-Fi or USB is enabled
-- We could alternatively check if lfs.attributes("/proc/sys/net/ipv4/conf/" .. os.getenv("INTERFACE"), "mode") == "directory" -- We could alternatively check if lfs.attributes("/proc/sys/net/ipv4/conf/" .. os.getenv("INTERFACE"), "mode") == "directory"
-- c.f., also what Cervantes does via /sys/class/net/eth0/carrier to check if the interface is up. -- c.f., also what Cervantes does via /sys/class/net/eth0/carrier to check if the interface is up.
-- That said, since we only care about whether *modules* are loaded, this does the job nicely. -- That said, since we only care about whether *modules* are loaded, this does the job nicely.

@ -158,6 +158,10 @@ function SonyPRSTUX:initNetworkManager(NetworkMgr)
self:showNetworkMenu(complete_callback) self:showNetworkMenu(complete_callback)
end end
function NetworkMgr:getNetworkInterfaceName()
return "wlan0"
end
NetworkMgr:setWirelessBackend("wpa_supplicant", {ctrl_interface = "/var/run/wpa_supplicant/wlan0"}) NetworkMgr:setWirelessBackend("wpa_supplicant", {ctrl_interface = "/var/run/wpa_supplicant/wlan0"})
function NetworkMgr:obtainIP() function NetworkMgr:obtainIP()

@ -62,9 +62,11 @@ local order = {
network = { network = {
"network_wifi", "network_wifi",
"network_proxy", "network_proxy",
"network_powersave",
"network_restore", "network_restore",
"network_info", "network_info",
"network_before_wifi_action", "network_before_wifi_action",
"network_after_wifi_action",
"network_dismiss_scan", "network_dismiss_scan",
"----------------------------", "----------------------------",
"ssh", "ssh",

@ -83,9 +83,11 @@ local order = {
network = { network = {
"network_wifi", "network_wifi",
"network_proxy", "network_proxy",
"network_powersave",
"network_restore", "network_restore",
"network_info", "network_info",
"network_before_wifi_action", "network_before_wifi_action",
"network_after_wifi_action",
"network_dismiss_scan", "network_dismiss_scan",
"----------------------------", "----------------------------",
"ssh", "ssh",

@ -2,6 +2,7 @@ local BD = require("ui/bidi")
local ConfirmBox = require("ui/widget/confirmbox") local ConfirmBox = require("ui/widget/confirmbox")
local DataStorage = require("datastorage") local DataStorage = require("datastorage")
local Device = require("device") local Device = require("device")
local Event = require("ui/event")
local InfoMessage = require("ui/widget/infomessage") local InfoMessage = require("ui/widget/infomessage")
local LuaSettings = require("luasettings") local LuaSettings = require("luasettings")
local UIManager = require("ui/uimanager") local UIManager = require("ui/uimanager")
@ -16,38 +17,80 @@ function NetworkMgr:readNWSettings()
self.nw_settings = LuaSettings:open(DataStorage:getSettingsDir().."/network.lua") self.nw_settings = LuaSettings:open(DataStorage:getSettingsDir().."/network.lua")
end end
-- Used after restoreWifiAsync() to make sure we eventually send a NetworkConnected event, as a few things rely on it (KOSync, c.f. #5109). -- Used after restoreWifiAsync() and the turn_on beforeWifiAction to make sure we eventually send a NetworkConnected event,
function NetworkMgr:connectivityCheck(iter) -- as quite a few things rely on it (KOSync, c.f. #5109; the network activity check, c.f., #6424).
-- Give up after a while... function NetworkMgr:connectivityCheck(iter, callback, widget)
if iter > 6 then -- Give up after a while (restoreWifiAsync can take over 45s, so, try to cover that)...
if iter > 25 then
logger.info("Failed to restore Wi-Fi (after", iter, "iterations)!")
self.wifi_was_on = false
G_reader_settings:saveSetting("wifi_was_on", false)
-- If we abort, murder Wi-Fi and the async script first...
if Device:hasWifiManager() and not Device:isEmulator() then
os.execute("pkill -TERM restore-wifi-async.sh 2>/dev/null")
end
NetworkMgr:turnOffWifi()
-- Handle the UI warning if it's from a beforeWifiAction...
if widget then
UIManager:close(widget)
UIManager:show(InfoMessage:new{ text = _("Error connecting to the network") })
end
return return
end end
if NetworkMgr:isWifiOn() and NetworkMgr:isConnected() then if NetworkMgr:isWifiOn() and NetworkMgr:isConnected() then
local Event = require("ui/event") self.wifi_was_on = true
G_reader_settings:saveSetting("wifi_was_on", true)
UIManager:broadcastEvent(Event:new("NetworkConnected")) UIManager:broadcastEvent(Event:new("NetworkConnected"))
logger.info("WiFi successfully restored!") logger.info("Wi-Fi successfully restored (after", iter, "iterations)!")
-- Handle the UI & callback if it's from a beforeWifiAction...
if widget then
UIManager:close(widget)
end
if callback then
callback()
else
-- If this trickled down from a turn_onbeforeWifiAction and there is no callback,
-- mention that the action needs to be retried manually.
if widget then
UIManager:show(InfoMessage:new{
text = _("You can now retry the action that required network access"),
timeout = 3,
})
end
end
else else
UIManager:scheduleIn(2, function() NetworkMgr:connectivityCheck(iter + 1) end) UIManager:scheduleIn(2, function() NetworkMgr:connectivityCheck(iter + 1, callback, widget) end)
end end
end end
function NetworkMgr:scheduleConnectivityCheck() function NetworkMgr:scheduleConnectivityCheck(callback, widget)
UIManager:scheduleIn(2, function() NetworkMgr:connectivityCheck(1) end) UIManager:scheduleIn(2, function() NetworkMgr:connectivityCheck(1, callback, widget) end)
end end
function NetworkMgr:init() function NetworkMgr:init()
-- On Kobo, kill WiFi if NetworkMgr:isWifiOn() and NOT NetworkMgr:isConnected() -- On Kobo, kill Wi-Fi if NetworkMgr:isWifiOn() and NOT NetworkMgr:isConnected()
-- (i.e., if the launcher left the WiFi in an inconsistent state: modules loaded, but no route to gateway). -- (i.e., if the launcher left the Wi-Fi in an inconsistent state: modules loaded, but no route to gateway).
if Device:isKobo() and self:isWifiOn() and not self:isConnected() then if Device:isKobo() and self:isWifiOn() and not self:isConnected() then
logger.info("Kobo WiFi: Left in an inconsistent state by launcher!") logger.info("Kobo Wi-Fi: Left in an inconsistent state by launcher!")
self:turnOffWifi() self:turnOffWifi()
end end
self.wifi_was_on = G_reader_settings:isTrue("wifi_was_on") 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 if self.wifi_was_on and G_reader_settings:isTrue("auto_restore_wifi") then
self:restoreWifiAsync() -- Don't bother if WiFi is already up...
if not (self:isWifiOn() and self:isConnected()) then
self:restoreWifiAsync()
end
self:scheduleConnectivityCheck() self:scheduleConnectivityCheck()
else
-- Trigger an initial NetworkConnected event if WiFi was already up when we were launched
if NetworkMgr:isWifiOn() and NetworkMgr:isConnected() then
-- NOTE: This needs to be delayed because NetworkListener is initialized slightly later by the FM/Reader app...
UIManager:scheduleIn(2, function() UIManager:broadcastEvent(Event:new("NetworkConnected")) end)
end
end end
end end
@ -57,6 +100,7 @@ end
function NetworkMgr:turnOnWifi() end function NetworkMgr:turnOnWifi() end
function NetworkMgr:turnOffWifi() end function NetworkMgr:turnOffWifi() end
function NetworkMgr:isWifiOn() end function NetworkMgr:isWifiOn() end
function NetworkMgr:getNetworkInterfaceName() end
function NetworkMgr:getNetworkList() end function NetworkMgr:getNetworkList() end
function NetworkMgr:getCurrentNetwork() end function NetworkMgr:getCurrentNetwork() end
function NetworkMgr:authenticateNetwork() end function NetworkMgr:authenticateNetwork() end
@ -92,32 +136,69 @@ function NetworkMgr:promptWifiOff(complete_callback)
end end
function NetworkMgr:turnOnWifiAndWaitForConnection(callback) function NetworkMgr:turnOnWifiAndWaitForConnection(callback)
NetworkMgr:turnOnWifi() local info = InfoMessage:new{ text = _("Connecting to Wi-Fi…") }
local timeout = 30
local retry_count = 0
local info = InfoMessage:new{ text = T(_("Enabling Wi-Fi. Waiting for Internet connection…\nTimeout %1 seconds."), timeout)}
UIManager:show(info) UIManager:show(info)
UIManager:forceRePaint() UIManager:forceRePaint()
while not NetworkMgr:isOnline() and retry_count < timeout do
ffiutil.sleep(1) -- Don't bother if WiFi is already up...
retry_count = retry_count + 1 if not (self:isWifiOn() and self:isConnected()) then
end self:turnOnWifi()
UIManager:close(info)
if retry_count == timeout then
UIManager:show(InfoMessage:new{ text = _("Error connecting to the network") })
return
end end
if callback then callback() 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)
end
--- This quirky internal flag is used for the rare beforeWifiAction -> afterWifiAction brackets.
function NetworkMgr:clearBeforeActionFlag()
self._before_action_tripped = nil
end
function NetworkMgr:setBeforeActionFlag()
self._before_action_tripped = true
end
function NetworkMgr:getBeforeActionFlag()
return self._before_action_tripped
end end
--- @note: The callback will only run *after* a *succesful* network connection.
--- The only guarantee it provides is isConnected (i.e., an IP & a local gateway),
--- *NOT* isOnline (i.e., WAN), se be careful with recursive callbacks!
function NetworkMgr:beforeWifiAction(callback) function NetworkMgr:beforeWifiAction(callback)
-- Remember that we ran, for afterWifiAction...
self:setBeforeActionFlag()
local wifi_enable_action = G_reader_settings:readSetting("wifi_enable_action") local wifi_enable_action = G_reader_settings:readSetting("wifi_enable_action")
if wifi_enable_action == "turn_on" then if wifi_enable_action == "turn_on" then
NetworkMgr:turnOnWifiAndWaitForConnection(callback) NetworkMgr:turnOnWifiAndWaitForConnection(callback)
else else
NetworkMgr:promptWifiOn(callback) NetworkMgr:promptWifiOn(callback)
end end
end end
-- NOTE: This is actually used very sparingly (newsdownloader/send2ebook),
-- because bracketing a single action in a connect/disconnect session doesn't necessarily make much sense...
function NetworkMgr:afterWifiAction(callback)
-- Don't do anything if beforeWifiAction never actually ran...
if not self:getBeforeActionFlag() then
return
end
self:clearBeforeActionFlag()
local wifi_disable_action = G_reader_settings:readSetting("wifi_disable_action")
if wifi_disable_action == "leave_on" then
-- NOP :)
if callback then
callback()
end
elseif wifi_disable_action == "turn_off" then
NetworkMgr:turnOffWifi(callback)
else
NetworkMgr:promptWifiOff(callback)
end
end
function NetworkMgr:isConnected() function NetworkMgr:isConnected()
if Device:isAndroid() or Device:isCervantes() or Device:isPocketBook() or Device:isEmulator() then if Device:isAndroid() or Device:isCervantes() or Device:isPocketBook() or Device:isEmulator() then
@ -174,6 +255,68 @@ function NetworkMgr:setHTTPProxy(proxy)
end end
end end
-- Helper functions to hide the quirks of using beforeWifiAction properly ;).
-- Run callback *now* if you're currently online (ie., isOnline),
-- or attempt to go online and run it *ASAP* without any more user interaction.
-- NOTE: If you're currently connected but without Internet access (i.e., isConnected and not isOnline),
-- it will just attempt to re-connect, *without* running the callback.
-- c.f., ReaderWikipedia:onShowWikipediaLookup @ frontend/apps/reader/modules/readerwikipedia.lua
function NetworkMgr:runWhenOnline(callback)
if self:isOnline() then
callback()
else
--- @note: Avoid infinite recursion, beforeWifiAction only guarantees isConnected, not isOnline.
if not self:isConnected() then
self:beforeWifiAction(callback)
else
self:beforeWifiAction()
end
end
end
-- This one is for callbacks that only require isConnected, and since that's guaranteed by beforeWifiAction,
-- you also have a guarantee that the callback *will* run.
function NetworkMgr:runWhenConnected(callback)
if self:isConnected() then
callback()
else
self:beforeWifiAction(callback)
end
end
-- Mild variants that are used for recursive calls at the beginning of a complex function call.
-- Returns true when not yet online, in which case you should *abort* (i.e., return) the initial call,
-- and otherwise, go-on as planned.
-- NOTE: If you're currently connected but without Internet access (i.e., isConnected and not isOnline),
-- it will just attempt to re-connect, *without* running the callback.
-- c.f., ReaderWikipedia:lookupWikipedia @ frontend/apps/reader/modules/readerwikipedia.lua
function NetworkMgr:willRerunWhenOnline(callback)
if not self:isOnline() then
--- @note: Avoid infinite recursion, beforeWifiAction only guarantees isConnected, not isOnline.
if not self:isConnected() then
self:beforeWifiAction(callback)
else
self:beforeWifiAction()
end
return true
end
return false
end
-- This one is for callbacks that only require isConnected, and since that's guaranteed by beforeWifiAction,
-- you also have a guarantee that the callback *will* run.
function NetworkMgr:willRerunWhenConnected(callback)
if not self:isConnected() then
self:beforeWifiAction(callback)
return true
end
return false
end
function NetworkMgr:getWifiMenuTable() function NetworkMgr:getWifiMenuTable()
if Device:isAndroid() then if Device:isAndroid() then
return { return {
@ -196,7 +339,6 @@ function NetworkMgr:getWifiToggleMenuTable()
local complete_callback = function() local complete_callback = function()
-- notify touch menu to update item check state -- notify touch menu to update item check state
touchmenu_instance:updateItems() touchmenu_instance:updateItems()
local Event = require("ui/event")
-- if wifi was on, this callback will only be executed when the network has been -- if wifi was on, this callback will only be executed when the network has been
-- disconnected. -- disconnected.
if wifi_status then if wifi_status then
@ -208,7 +350,7 @@ function NetworkMgr:getWifiToggleMenuTable()
if NetworkMgr:isWifiOn() and NetworkMgr:isConnected() then if NetworkMgr:isWifiOn() and NetworkMgr:isConnected() then
UIManager:broadcastEvent(Event:new("NetworkConnected")) UIManager:broadcastEvent(Event:new("NetworkConnected"))
elseif NetworkMgr:isWifiOn() and not NetworkMgr:isConnected() then elseif NetworkMgr:isWifiOn() and not NetworkMgr:isConnected() then
-- Don't leave WiFi in an inconsistent state if the connection failed. -- Don't leave Wi-Fi in an inconsistent state if the connection failed.
self.wifi_was_on = false self.wifi_was_on = false
G_reader_settings:saveSetting("wifi_was_on", false) G_reader_settings:saveSetting("wifi_was_on", false)
-- NOTE: We're limiting this to only a few platforms, as it might be actually harmful on some devices. -- NOTE: We're limiting this to only a few platforms, as it might be actually harmful on some devices.
@ -219,8 +361,8 @@ function NetworkMgr:getWifiToggleMenuTable()
-- Kobo: Yes, please. -- Kobo: Yes, please.
-- Cervantes: Loads/unloads module, probably could use it like Kobo. -- Cervantes: Loads/unloads module, probably could use it like Kobo.
-- Kindle: Probably could use it, if only because leaving Wireless on is generally a terrible idea on Kindle, -- Kindle: Probably could use it, if only because leaving Wireless on is generally a terrible idea on Kindle,
-- except that we defer to lipc, which makes WiFi handling asynchronous, and the callback is simply delayed by 1s, -- except that we defer to lipc, which makes Wi-Fi handling asynchronous, and the callback is simply delayed by 1s,
-- so we can't be sure the system will actually have finished bringing WiFi up by then... -- so we can't be sure the system will actually have finished bringing Wi-Fi up by then...
NetworkMgr:turnOffWifi() NetworkMgr:turnOffWifi()
touchmenu_instance:updateItems() touchmenu_instance:updateItems()
end end
@ -276,9 +418,26 @@ function NetworkMgr:getProxyMenuTable()
} }
end end
function NetworkMgr:getPowersaveMenuTable()
return {
text = _("Kill 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.]]),
checked_func = function() return G_reader_settings:isTrue("auto_disable_wifi") end,
enabled_func = function() return Device:hasWifiManager() and not Device:isEmulator() end,
callback = function()
G_reader_settings:flipNilOrFalse("auto_disable_wifi")
-- NOTE: Well, not exactly, but the activity check wouldn't be (un)scheduled until the next Network(Dis)Connected event...
UIManager:show(InfoMessage:new{
text = _("This will take effect on next restart."),
})
end,
}
end
function NetworkMgr:getRestoreMenuTable() function NetworkMgr:getRestoreMenuTable()
return { return {
text = _("Automatically restore Wi-Fi connection after resume"), 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, checked_func = function() return G_reader_settings:isTrue("auto_restore_wifi") end,
enabled_func = function() return Device:hasWifiManager() and not Device:isEmulator() end, enabled_func = function() return Device:hasWifiManager() and not Device:isEmulator() end,
callback = function() G_reader_settings:flipNilOrFalse("auto_restore_wifi") end, callback = function() G_reader_settings:flipNilOrFalse("auto_restore_wifi") end,
@ -306,34 +465,67 @@ function NetworkMgr:getInfoMenuTable()
end end
function NetworkMgr:getBeforeWifiActionMenuTable() function NetworkMgr:getBeforeWifiActionMenuTable()
local wifi_enable_action_setting = G_reader_settings:readSetting("wifi_enable_action") or "prompt" local wifi_enable_action_setting = G_reader_settings:readSetting("wifi_enable_action") or "prompt"
local wifi_enable_actions = { local wifi_enable_actions = {
turn_on = {_("turn on"), _("Turn on (experimental)")}, turn_on = {_("turn on"), _("Turn on")},
prompt = {_("prompt"), _("Prompt")}, prompt = {_("prompt"), _("Prompt")},
} }
local action_table = function(wifi_enable_action) local action_table = function(wifi_enable_action)
return { return {
text = wifi_enable_actions[wifi_enable_action][2], text = wifi_enable_actions[wifi_enable_action][2],
checked_func = function() checked_func = function()
return wifi_enable_action_setting == wifi_enable_action return wifi_enable_action_setting == wifi_enable_action
end, end,
callback = function() callback = function()
wifi_enable_action_setting = wifi_enable_action wifi_enable_action_setting = wifi_enable_action
G_reader_settings:saveSetting("wifi_enable_action", wifi_enable_action) G_reader_settings:saveSetting("wifi_enable_action", wifi_enable_action)
end, end,
} }
end end
return { return {
text_func = function() text_func = function()
return T(_("Action when Wi-Fi is off: %1"), return T(_("Action when Wi-Fi is off: %1"),
wifi_enable_actions[wifi_enable_action_setting][1] wifi_enable_actions[wifi_enable_action_setting][1]
) )
end, end,
sub_item_table = { sub_item_table = {
action_table("turn_on"), action_table("turn_on"),
action_table("prompt"), action_table("prompt"),
} }
} }
end
function NetworkMgr:getAfterWifiActionMenuTable()
local wifi_disable_action_setting = G_reader_settings:readSetting("wifi_disable_action") or "prompt"
local wifi_disable_actions = {
leave_on = {_("leave on"), _("Leave on")},
turn_off = {_("turn off"), _("Turn off")},
prompt = {_("prompt"), _("Prompt")},
}
local action_table = function(wifi_disable_action)
return {
text = wifi_disable_actions[wifi_disable_action][2],
checked_func = function()
return wifi_disable_action_setting == wifi_disable_action
end,
callback = function()
wifi_disable_action_setting = wifi_disable_action
G_reader_settings:saveSetting("wifi_disable_action", wifi_disable_action)
end,
}
end
return {
text_func = function()
return T(_("Action when done with Wi-Fi: %1"),
wifi_disable_actions[wifi_disable_action_setting][1]
)
end,
sub_item_table = {
action_table("leave_on"),
action_table("turn_off"),
action_table("prompt"),
}
}
end end
function NetworkMgr:getDismissScanMenuTable() function NetworkMgr:getDismissScanMenuTable()
@ -354,9 +546,11 @@ function NetworkMgr:getMenuTable(common_settings)
common_settings.network_info = self:getInfoMenuTable() common_settings.network_info = self:getInfoMenuTable()
if Device:hasWifiManager() then if Device:hasWifiManager() then
common_settings.network_powersave = self:getPowersaveMenuTable()
common_settings.network_restore = self:getRestoreMenuTable() common_settings.network_restore = self:getRestoreMenuTable()
common_settings.network_dismiss_scan = self:getDismissScanMenuTable() common_settings.network_dismiss_scan = self:getDismissScanMenuTable()
common_settings.network_before_wifi_action = self:getBeforeWifiActionMenuTable() common_settings.network_before_wifi_action = self:getBeforeWifiActionMenuTable()
common_settings.network_after_wifi_action = self:getAfterWifiActionMenuTable()
end end
end end
@ -458,6 +652,7 @@ if NETWORK_PROXY then
NetworkMgr:setHTTPProxy(NETWORK_PROXY) NetworkMgr:setHTTPProxy(NETWORK_PROXY)
end end
Device:initNetworkManager(NetworkMgr) Device:initNetworkManager(NetworkMgr)
NetworkMgr:init() NetworkMgr:init()

@ -1,8 +1,11 @@
local BD = require("ui/bidi") local BD = require("ui/bidi")
local Device = require("device")
local Event = require("ui/event")
local InfoMessage = require("ui/widget/infomessage") local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer") local InputContainer = require("ui/widget/container/inputcontainer")
local NetworkMgr = require("ui/network/manager") local NetworkMgr = require("ui/network/manager")
local UIManager = require("ui/uimanager") local UIManager = require("ui/uimanager")
local logger = require("logger")
local _ = require("gettext") local _ = require("gettext")
local T = require("ffi/util").template local T = require("ffi/util").template
@ -16,10 +19,17 @@ function NetworkListener:onToggleWifi()
}) })
-- NB Normal widgets should use NetworkMgr:promptWifiOn() -- NB Normal widgets should use NetworkMgr:promptWifiOn()
-- This is specifically the toggle wifi action, so consent is implied. -- (or, better yet, the NetworkMgr:beforeWifiAction wrappers: NetworkMgr:runWhenOnline() & co.)
NetworkMgr:turnOnWifi() -- 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)
else else
NetworkMgr:turnOffWifi() local complete_callback = function()
UIManager:broadcastEvent(Event:new("NetworkDisconnected"))
end
NetworkMgr:turnOffWifi(complete_callback)
UIManager:show(InfoMessage:new{ UIManager:show(InfoMessage:new{
text = _("Wi-Fi off."), text = _("Wi-Fi off."),
@ -29,8 +39,11 @@ function NetworkListener:onToggleWifi()
end end
function NetworkListener:onInfoWifiOff() function NetworkListener:onInfoWifiOff()
-- can't hurt -- That's the end goal
NetworkMgr:turnOffWifi() local complete_callback = function()
UIManager:broadcastEvent(Event:new("NetworkDisconnected"))
end
NetworkMgr:turnOffWifi(complete_callback)
UIManager:show(InfoMessage:new{ UIManager:show(InfoMessage:new{
text = _("Wi-Fi off."), text = _("Wi-Fi off."),
@ -46,8 +59,12 @@ function NetworkListener:onInfoWifiOn()
}) })
-- NB Normal widgets should use NetworkMgr:promptWifiOn() -- 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. -- This is specifically the toggle Wi-Fi action, so consent is implied.
NetworkMgr:turnOnWifi() local complete_callback = function()
UIManager:broadcastEvent(Event:new("NetworkConnected"))
end
NetworkMgr:turnOnWifi(complete_callback)
else else
local info_text local info_text
local current_network = NetworkMgr:getCurrentNetwork() local current_network = NetworkMgr:getCurrentNetwork()
@ -64,4 +81,136 @@ function NetworkListener:onInfoWifiOn()
end end
end end
-- Everything below is to handle auto_disable_wifi ;).
local default_network_timeout_seconds = 5*60
local max_network_timeout_seconds = 30*60
-- This should be more than enough to catch actual activity vs. noise spread over 5 minutes.
local network_activity_noise_margin = 12 -- unscaled_size_check: ignore
-- Read the statistics/tx_packets sysfs entry for the current network interface.
-- It *should* be the least noisy entry on an idle network...
-- The fact that auto_disable_wifi is only available on (Device:hasWifiManager() and not Device:isEmulator())
-- allows us to get away with a Linux-only solution.
function NetworkListener:_getTxPackets()
-- read tx_packets stats from sysfs (for the right network if)
local file = io.open("/sys/class/net/" .. NetworkMgr:getNetworkInterfaceName() .. "/statistics/tx_packets", "rb")
-- file exists only when Wi-Fi module is loaded.
if not file then return nil end
local out = file:read("*all")
file:close()
-- strip NaN from file read (i.e.,: line endings, error messages)
local tx_packets
if type(out) ~= "number" then
tx_packets = tonumber(out)
else
tx_packets = out
end
-- finally return it
if type(tx_packets) == "number" then
return tx_packets
else
return nil
end
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
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
end
if self._activity_check_delay then
self._activity_check_delay = nil
end
end
function NetworkListener:_scheduleActivityCheck()
logger.dbg("NetworkListener: network activity check")
local keep_checking = true
local tx_packets = NetworkListener:_getTxPackets()
if self._last_tx_packets then
-- Compute noise margin based on the current delay
local delay = self._activity_check_delay or default_network_timeout_seconds
local noise = delay / default_network_timeout_seconds * network_activity_noise_margin
-- If there was no meaningful activity (+/- a couple packets), kill the Wi-Fi
if math.max(0, tx_packets - noise) <= self._last_tx_packets then
logger.dbg("NetworkListener: No meaningful network activity ( then:", self._last_tx_packets, "vs. now:", tx_packets, "), disabling Wi-Fi")
keep_checking = false
local complete_callback = function()
UIManager:broadcastEvent(Event:new("NetworkDisconnected"))
end
NetworkMgr:turnOffWifi(complete_callback)
-- NOTE: We leave wifi_was_on as-is on purpose, we wouldn't want to break auto_restore_wifi workflows on the next start...
end
end
-- If we've just killed Wi-Fi, onNetworkDisconnected will take care of unscheduling us
if keep_checking then
-- Update tracker for next iter
self._last_tx_packets = tx_packets
-- If it's already been scheduled, increase the delay until we hit the ceiling
if self._activity_check_delay then
self._activity_check_delay = self._activity_check_delay + default_network_timeout_seconds
if self._activity_check_delay > max_network_timeout_seconds then
self._activity_check_delay = max_network_timeout_seconds
end
else
self._activity_check_delay = default_network_timeout_seconds
end
UIManager:scheduleIn(self._activity_check_delay, self._scheduleActivityCheck, self)
self._activity_check_scheduled = true
logger.dbg("NetworkListener: network activity check scheduled in", self._activity_check_delay, "seconds")
end
end
function NetworkListener:onNetworkConnected()
if not (Device:hasWifiManager() and not Device:isEmulator()) then
return
end
if not G_reader_settings:isTrue("auto_disable_wifi") then
return
end
-- If the activity check has already been scheduled for some reason, unschedule it first.
NetworkListener:_unscheduleActivityCheck()
NetworkListener:_scheduleActivityCheck()
end
function NetworkListener:onNetworkDisconnected()
if not (Device:hasWifiManager() and not Device:isEmulator()) then
return
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()
end
return NetworkListener return NetworkListener

@ -455,21 +455,19 @@ function OTAManager:getOTAMenuTable()
return { return {
text = _("Update"), text = _("Update"),
hold_callback = function() hold_callback = function()
if not NetworkMgr:isOnline() then local connect_callback = function()
NetworkMgr:promptWifiOn()
else
OTAManager:fetchAndProcessUpdate() OTAManager:fetchAndProcessUpdate()
end end
NetworkMgr:runWhenOnline(connect_callback)
end, end,
sub_item_table = { sub_item_table = {
{ {
text = _("Check for update"), text = _("Check for update"),
callback = function() callback = function()
if not NetworkMgr:isOnline() then local connect_callback = function()
NetworkMgr:promptWifiOn()
else
OTAManager:fetchAndProcessUpdate() OTAManager:fetchAndProcessUpdate()
end end
NetworkMgr:runWhenOnline(connect_callback)
end end
}, },
{ {

@ -416,10 +416,10 @@ Show translated text in TextViewer, with alternate translations
--]] --]]
function Translator:showTranslation(text, target_lang, source_lang) function Translator:showTranslation(text, target_lang, source_lang)
local NetworkMgr = require("ui/network/manager") local NetworkMgr = require("ui/network/manager")
if not NetworkMgr:isOnline() then if NetworkMgr:willRerunWhenOnline(function() self:showTranslation(text, target_lang, source_lang) end) then
NetworkMgr:promptWifiOn()
return return
end end
-- Wrap next function with Trapper to be able to interrupt -- Wrap next function with Trapper to be able to interrupt
-- translation service query. -- translation service query.
local Trapper = require("ui/trapper") local Trapper = require("ui/trapper")

@ -22,9 +22,12 @@ Example:
UIManager:show(require("ui/widget/networksetting"):new{ UIManager:show(require("ui/widget/networksetting"):new{
network_list = network_list, network_list = network_list,
connect_callback = function() connect_callback = function()
-- connect_callback will be called when an connect/disconnect -- connect_callback will be called when a *connect* (NOT disconnect)
-- attempt has been made. you can update UI widgets in the -- attempt has been successful.
-- callback. -- You can update UI widgets in the callback.
end,
disconnect_callback = function()
-- This one will fire unconditionally after a disconnect attempt.
end, end,
}) })
@ -224,7 +227,8 @@ function NetworkItem:connect()
text = err_msg text = err_msg
end end
if self.setting_ui.connect_callback then -- Do what it says on the tin, and only trigger the connect_callback on a *successful* connect.
if success and self.setting_ui.connect_callback then
self.setting_ui.connect_callback() self.setting_ui.connect_callback()
end end
@ -244,8 +248,8 @@ function NetworkItem:disconnect()
self.info.connected = nil self.info.connected = nil
self:refresh() self:refresh()
self.setting_ui:setConnectedItem(nil) self.setting_ui:setConnectedItem(nil)
if self.setting_ui.connect_callback then if self.setting_ui.disconnect_callback then
self.setting_ui.connect_callback() self.setting_ui.disconnect_callback()
end end
end end
@ -378,6 +382,7 @@ local NetworkSetting = InputContainer:new{
-- } -- }
network_list = nil, network_list = nil,
connect_callback = nil, connect_callback = nil,
disconnect_callback = nil,
} }
function NetworkSetting:init() function NetworkSetting:init()

@ -377,10 +377,7 @@ end
function OPDSBrowser:getCatalog(item_url, username, password) function OPDSBrowser:getCatalog(item_url, username, password)
local ok, catalog = pcall(self.parseFeed, self, item_url, username, password) local ok, catalog = pcall(self.parseFeed, self, item_url, username, password)
if not ok and catalog and not NetworkMgr:isOnline() then if not ok and catalog then
NetworkMgr:promptWifiOn()
return
elseif not ok and catalog then
logger.info("cannot get catalog info from", item_url, catalog) logger.info("cannot get catalog info from", item_url, catalog)
UIManager:show(InfoMessage:new{ UIManager:show(InfoMessage:new{
text = T(_("Cannot get catalog info from %1"), (BD.url(item_url) or "")), text = T(_("Cannot get catalog info from %1"), (BD.url(item_url) or "")),
@ -724,11 +721,17 @@ function OPDSBrowser:onMenuSelect(item)
self:showDownloads(item) self:showDownloads(item)
-- navigation -- navigation
else else
local connect_callback
if item.searchable then if item.searchable then
self:browseSearchable(item.url, item.username, item.password) connect_callback = function()
self:browseSearchable(item.url, item.username, item.password)
end
else else
self:browse(item.url, item.username, item.password) connect_callback = function()
self:browse(item.url, item.username, item.password)
end
end end
NetworkMgr:runWhenConnected(connect_callback)
end end
return true return true
end end

@ -21,11 +21,11 @@ EOF
} }
RestoreWifi() { RestoreWifi() {
echo "[$(date)] restore-wifi-async.sh: Restarting WiFi" echo "[$(date)] restore-wifi-async.sh: Restarting Wi-Fi"
./enable-wifi.sh ./enable-wifi.sh
RunWpaCli RunWpaCli
./obtain-ip.sh ./obtain-ip.sh
echo "[$(date)] restore-wifi-async.sh: Restarted WiFi" echo "[$(date)] restore-wifi-async.sh: Restarted Wi-Fi"
} }
RestoreWifi & RestoreWifi &

@ -1,8 +1,38 @@
#!/bin/sh #!/bin/sh
# Disable wifi, and remove all modules. # Disable wifi, and remove all modules.
# NOTE: Save our resolv.conf to avoid ending up with an empty one, in case the DHCP client wipes it on release (#6424).
cp -a "/etc/resolv.conf" "/tmp/resolv.ko"
old_hash="$(md5sum "/etc/resolv.conf" | cut -f1 -d' ')"
killall udhcpc default.script wpa_supplicant 2>/dev/null if [ -x "/sbin/dhcpcd" ]; then
env -u LD_LIBRARY_PATH dhcpcd -d -k "${INTERFACE}"
killall -q -TERM udhcpc default.script
else
killall -q -TERM udhcpc default.script dhcpcd
fi
# NOTE: dhcpcd -k waits for the signalled process to die, but busybox's killall doesn't have a -w, --wait flag,
# so we have to wait for udhcpc to die ourselves...
kill_timeout=0
while pkill -0 udhcpc; do
# Stop waiting after 5s
if [ ${kill_timeout} -ge 20 ]; then
break
fi
usleep 250000
kill_timeout=$((kill_timeout + 1))
done
new_hash="$(md5sum "/etc/resolv.conf" | cut -f1 -d' ')"
# Restore our network-specific resolv.conf if the DHCP client wiped it when releasing the lease...
if [ "${new_hash}" != "${old_hash}" ]; then
mv -f "/tmp/resolv.ko" "/etc/resolv.conf"
else
rm -f "/tmp/resolv.ko"
fi
wpa_cli terminate
[ "${WIFI_MODULE}" != "8189fs" ] && [ "${WIFI_MODULE}" != "8192es" ] && wlarm_le -i "${INTERFACE}" down [ "${WIFI_MODULE}" != "8189fs" ] && [ "${WIFI_MODULE}" != "8192es" ] && wlarm_le -i "${INTERFACE}" down
ifconfig "${INTERFACE}" down ifconfig "${INTERFACE}" down

@ -1,7 +1,6 @@
#!/bin/sh #!/bin/sh
# Load wifi modules and enable wifi. # Load wifi modules and enable wifi.
lsmod | grep -q sdio_wifi_pwr || insmod "/drivers/${PLATFORM}/wifi/sdio_wifi_pwr.ko" lsmod | grep -q sdio_wifi_pwr || insmod "/drivers/${PLATFORM}/wifi/sdio_wifi_pwr.ko"
# Moar sleep! # Moar sleep!
usleep 250000 usleep 250000
@ -13,6 +12,6 @@ sleep 1
ifconfig "${INTERFACE}" up ifconfig "${INTERFACE}" up
[ "${WIFI_MODULE}" != "8189fs" ] && [ "${WIFI_MODULE}" != "8192es" ] && wlarm_le -i "${INTERFACE}" up [ "${WIFI_MODULE}" != "8189fs" ] && [ "${WIFI_MODULE}" != "8192es" ] && wlarm_le -i "${INTERFACE}" up
pidof wpa_supplicant >/dev/null || pkill -0 wpa_supplicant ||
env -u LD_LIBRARY_PATH \ env -u LD_LIBRARY_PATH \
wpa_supplicant -D wext -s -i "${INTERFACE}" -O /var/run/wpa_supplicant -c /etc/wpa_supplicant/wpa_supplicant.conf -B wpa_supplicant -D wext -s -i "${INTERFACE}" -c /etc/wpa_supplicant/wpa_supplicant.conf -O /var/run/wpa_supplicant -B

@ -110,7 +110,11 @@ if [ "${VIA_NICKEL}" = "true" ]; then
sync sync
# And we can now stop the full Kobo software stack # And we can now stop the full Kobo software stack
# NOTE: We don't need to kill KFMon, it's smart enough not to allow running anything else while we're up # NOTE: We don't need to kill KFMon, it's smart enough not to allow running anything else while we're up
killall -TERM nickel hindenburg sickel fickel adobehost fmon 2>/dev/null # NOTE: We kill Nickel's master dhcpcd daemon on purpose,
# as we want to be able to use our own per-if processes w/ custom args later on.
# A SIGTERM does not break anything, it'll just prevent automatic lease renewal until the time
# KOReader actually sets the if up itself (i.e., it'll do)...
killall -q -TERM nickel hindenburg sickel fickel adobehost dhcpcd-dbus dhcpcd fmon
fi fi
# fallback for old fmon, KFMon and advboot users (-> if no args were passed to the script, start the FM) # fallback for old fmon, KFMon and advboot users (-> if no args were passed to the script, start the FM)
@ -131,7 +135,7 @@ if [ -z "${PRODUCT}" ]; then
export PRODUCT export PRODUCT
fi fi
# PLATFORM is used in koreader for the path to the WiFi drivers (as well as when restarting nickel) # PLATFORM is used in koreader for the path to the Wi-Fi drivers (as well as when restarting nickel)
if [ -z "${PLATFORM}" ]; then if [ -z "${PLATFORM}" ]; then
# shellcheck disable=SC2046 # shellcheck disable=SC2046
export $(grep -s -e '^PLATFORM=' "/proc/$(pidof -s udevd)/environ") export $(grep -s -e '^PLATFORM=' "/proc/$(pidof -s udevd)/environ")
@ -209,6 +213,16 @@ ko_do_fbdepth() {
fi fi
} }
# Ensure we start with a valid nameserver in resolv.conf, otherwise we're stuck with broken name resolution (#6421, #6424).
# Fun fact: this wouldn't be necessary if Kobo were using a non-prehistoric glibc... (it was fixed in glibc 2.26).
ko_do_dns() {
# If there aren't any servers listed, append CloudFlare's
if not grep -q '^nameserver' "/etc/resolv.conf"; then
echo "# Added by KOReader because your setup is broken" >>"/etc/resolv.conf"
echo "nameserver 1.1.1.1" >>"/etc/resolv.conf"
fi
}
# Remount the SD card RW if it's inserted and currently RO # Remount the SD card RW if it's inserted and currently RO
if awk '$4~/(^|,)ro($|,)/' /proc/mounts | grep ' /mnt/sd '; then if awk '$4~/(^|,)ro($|,)/' /proc/mounts | grep ' /mnt/sd '; then
mount -o remount,rw /mnt/sd mount -o remount,rw /mnt/sd
@ -232,6 +246,8 @@ while [ ${RETURN_VALUE} -ne 0 ]; do
ko_update_check ko_update_check
# Do or double-check the fb depth switch, or restore original bitdepth if requested # Do or double-check the fb depth switch, or restore original bitdepth if requested
ko_do_fbdepth ko_do_fbdepth
# Make sure we have a sane resolv.conf
ko_do_dns
fi fi
./reader.lua "${args}" >>crash.log 2>&1 ./reader.lua "${args}" >>crash.log 2>&1
@ -273,11 +289,11 @@ while [ ${RETURN_VALUE} -ne 0 ]; do
fi fi
# U+1F4A3, the hard way, because we can't use \u or \U escape sequences... # U+1F4A3, the hard way, because we can't use \u or \U escape sequences...
# shellcheck disable=SC2039 # shellcheck disable=SC2039
./fbink -q -b -O -m -t regular=./fonts/freefont/FreeSerif.ttf,px=${bombHeight},top=${bombMargin} $'\xf0\x9f\x92\xa3' ./fbink -q -b -O -m -t regular=./fonts/freefont/FreeSerif.ttf,px=${bombHeight},top=${bombMargin} -- $'\xf0\x9f\x92\xa3'
# And then print the tail end of the log on the bottom of the screen... # And then print the tail end of the log on the bottom of the screen...
crashLog="$(tail -n 25 crash.log | sed -e 's/\t/ /g')" crashLog="$(tail -n 25 crash.log | sed -e 's/\t/ /g')"
# The idea for the margins being to leave enough room for an fbink -Z bar, small horizontal margins, and a font size based on what 6pt looked like @ 265dpi # The idea for the margins being to leave enough room for an fbink -Z bar, small horizontal margins, and a font size based on what 6pt looked like @ 265dpi
./fbink -q -b -O -t regular=./fonts/droid/DroidSansMono.ttf,top=$((viewHeight / 2 + FONTH * 2 + FONTH / 2)),left=$((viewWidth / 60)),right=$((viewWidth / 60)),px=$((viewHeight / 64)) "${crashLog}" ./fbink -q -b -O -t regular=./fonts/droid/DroidSansMono.ttf,top=$((viewHeight / 2 + FONTH * 2 + FONTH / 2)),left=$((viewWidth / 60)),right=$((viewWidth / 60)),px=$((viewHeight / 64)) -- "${crashLog}"
# So far, we hadn't triggered an actual screen refresh, do that now, to make sure everything is bundled in a single flashing refresh. # So far, we hadn't triggered an actual screen refresh, do that now, to make sure everything is bundled in a single flashing refresh.
./fbink -q -f -s ./fbink -q -f -s
# Cue a lemming's faceplant sound effect! # Cue a lemming's faceplant sound effect!

@ -21,10 +21,38 @@ unset KO_NO_CBB
/etc/init.d/on-animator.sh /etc/init.d/on-animator.sh
) & ) &
# Make sure we kill the WiFi first, because nickel apparently doesn't like it if it's up... (cf. #1520) # Make sure we kill the Wi-Fi first, because nickel apparently doesn't like it if it's up... (cf. #1520)
# NOTE: That check is possibly wrong on PLATFORM == freescale (because I don't know if the sdio_wifi_pwr module exists there), but we don't terribly care about that. # NOTE: That check is possibly wrong on PLATFORM == freescale (because I don't know if the sdio_wifi_pwr module exists there), but we don't terribly care about that.
if lsmod | grep -q sdio_wifi_pwr; then if lsmod | grep -q sdio_wifi_pwr; then
killall restore-wifi-async.sh enable-wifi.sh obtain-ip.sh udhcpc default.script wpa_supplicant 2>/dev/null killall -q -TERM restore-wifi-async.sh enable-wifi.sh obtain-ip.sh
cp -a "/etc/resolv.conf" "/tmp/resolv.ko"
old_hash="$(md5sum "/etc/resolv.conf" | cut -f1 -d' ')"
if [ -x "/sbin/dhcpcd" ]; then
env -u LD_LIBRARY_PATH dhcpcd -d -k "${INTERFACE}"
killall -q -TERM udhcpc default.script
else
killall -q -TERM udhcpc default.script dhcpcd
fi
# NOTE: dhcpcd -k waits for the signalled process to die, but busybox's killall doesn't have a -w, --wait flag,
# so we have to wait for udhcpc to die ourselves...
kill_timeout=0
while pkill -0 udhcpc; do
# Stop waiting after 5s
if [ ${kill_timeout} -ge 20 ]; then
break
fi
usleep 250000
kill_timeout=$((kill_timeout + 1))
done
new_hash="$(md5sum "/etc/resolv.conf" | cut -f1 -d' ')"
# Restore our network-specific resolv.conf if the DHCP client wiped it when releasing the lease...
if [ "${new_hash}" != "${old_hash}" ]; then
mv -f "/tmp/resolv.ko" "/etc/resolv.conf"
else
rm -f "/tmp/resolv.ko"
fi
wpa_cli terminate
[ "${WIFI_MODULE}" != "8189fs" ] && [ "${WIFI_MODULE}" != "8192es" ] && wlarm_le -i "${INTERFACE}" down [ "${WIFI_MODULE}" != "8189fs" ] && [ "${WIFI_MODULE}" != "8192es" ] && wlarm_le -i "${INTERFACE}" down
ifconfig "${INTERFACE}" down ifconfig "${INTERFACE}" down
# NOTE: Kobo's busybox build is weird. rmmod appears to be modprobe in disguise, defaulting to the -r flag... # NOTE: Kobo's busybox build is weird. rmmod appears to be modprobe in disguise, defaulting to the -r flag...

@ -2,5 +2,10 @@
./release-ip.sh ./release-ip.sh
# Use udhcpc to obtain IP. # NOTE: Prefer dhcpcd over udhcpc if available. That's what Nickel uses,
env -u LD_LIBRARY_PATH udhcpc -S -i "${INTERFACE}" -s /etc/udhcpc.d/default.script -t15 -T10 -A3 -b -q # and udhcpc appears to trip some insanely wonky corner cases on current FW (#6421)
if [ -x "/sbin/dhcpcd" ]; then
env -u LD_LIBRARY_PATH dhcpcd -d -t 30 -w "${INTERFACE}"
else
env -u LD_LIBRARY_PATH udhcpc -S -i "${INTERFACE}" -s /etc/udhcpc.d/default.script -b -q
fi

@ -1,8 +1,34 @@
#!/bin/sh #!/bin/sh
# PATH export is only needed if you run this script manually from a shell
export PATH="${PATH}:/sbin"
# Release IP and shutdown udhcpc. # Release IP and shutdown udhcpc.
pkill -9 -f '/bin/sh /etc/udhcpc.d/default.script' # NOTE: Save our resolv.conf to avoid ending up with an empty one, in case the DHCP client wipes it on release (#6424).
ifconfig "${INTERFACE}" 0.0.0.0 cp -a "/etc/resolv.conf" "/tmp/resolv.ko"
old_hash="$(md5sum "/etc/resolv.conf" | cut -f1 -d' ')"
if [ -x "/sbin/dhcpcd" ]; then
env -u LD_LIBRARY_PATH dhcpcd -d -k "${INTERFACE}"
killall -q -TERM udhcpc default.script
else
killall -q -TERM udhcpc default.script dhcpcd
ifconfig "${INTERFACE}" 0.0.0.0
fi
# NOTE: dhcpcd -k waits for the signalled process to die, but busybox's killall doesn't have a -w, --wait flag,
# so we have to wait for udhcpc to die ourselves...
kill_timeout=0
while pkill -0 udhcpc; do
# Stop waiting after 5s
if [ ${kill_timeout} -ge 20 ]; then
break
fi
usleep 250000
kill_timeout=$((kill_timeout + 1))
done
new_hash="$(md5sum "/etc/resolv.conf" | cut -f1 -d' ')"
# Restore our network-specific resolv.conf if the DHCP client wiped it when releasing the lease...
if [ "${new_hash}" != "${old_hash}" ]; then
mv -f "/tmp/resolv.ko" "/etc/resolv.conf"
else
rm -f "/tmp/resolv.ko"
fi

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
RestoreWifi() { RestoreWifi() {
echo "[$(date)] restore-wifi-async.sh: Restarting WiFi" echo "[$(date)] restore-wifi-async.sh: Restarting Wi-Fi"
./enable-wifi.sh ./enable-wifi.sh
@ -9,8 +9,8 @@ RestoreWifi() {
# Pilfered from https://github.com/shermp/Kobo-UNCaGED/pull/21 ;) # Pilfered from https://github.com/shermp/Kobo-UNCaGED/pull/21 ;)
wpac_timeout=0 wpac_timeout=0
while ! wpa_cli status | grep -q "wpa_state=COMPLETED"; do while ! wpa_cli status | grep -q "wpa_state=COMPLETED"; do
# If wpa_supplicant hasn't connected within 10 seconds, assume it never will, and tear down WiFi # If wpa_supplicant hasn't connected within 15 seconds, assume it never will, and tear down Wi-Fi
if [ ${wpac_timeout} -ge 40 ]; then if [ ${wpac_timeout} -ge 60 ]; then
echo "[$(date)] restore-wifi-async.sh: Failed to connect to preferred AP!" echo "[$(date)] restore-wifi-async.sh: Failed to connect to preferred AP!"
./disable-wifi.sh ./disable-wifi.sh
return 1 return 1
@ -21,7 +21,7 @@ RestoreWifi() {
./obtain-ip.sh ./obtain-ip.sh
echo "[$(date)] restore-wifi-async.sh: Restarted WiFi" echo "[$(date)] restore-wifi-async.sh: Restarted Wi-Fi"
} }
RestoreWifi & RestoreWifi &

@ -1,6 +1,6 @@
# General # General
When connected to WiFi you can find the IP address and root password for your When connected to Wi-Fi you can find the IP address and root password for your
reMarkable in Settings -> About, then scroll down the GPLv3 compliance on the reMarkable in Settings -> About, then scroll down the GPLv3 compliance on the
right (finger drag scroll, not the page forward/back buttons). This should also right (finger drag scroll, not the page forward/back buttons). This should also
work for the USB network you get if you connect the reMarkable to your computer work for the USB network you get if you connect the reMarkable to your computer

@ -178,11 +178,11 @@ while [ ${RETURN_VALUE} -ne 0 ]; do
fi fi
# U+1F4A3, the hard way, because we can't use \u or \U escape sequences... # U+1F4A3, the hard way, because we can't use \u or \U escape sequences...
# shellcheck disable=SC2039 # shellcheck disable=SC2039
./fbink -q -b -O -m -t regular=./fonts/freefont/FreeSerif.ttf,px=${bombHeight},top=${bombMargin} $'\xf0\x9f\x92\xa3' ./fbink -q -b -O -m -t regular=./fonts/freefont/FreeSerif.ttf,px=${bombHeight},top=${bombMargin} -- $'\xf0\x9f\x92\xa3'
# And then print the tail end of the log on the bottom of the screen... # And then print the tail end of the log on the bottom of the screen...
crashLog="$(tail -n 25 crash.log | sed -e 's/\t/ /g')" crashLog="$(tail -n 25 crash.log | sed -e 's/\t/ /g')"
# The idea for the margins being to leave enough room for an fbink -Z bar, small horizontal margins, and a font size based on what 6pt looked like @ 265dpi # The idea for the margins being to leave enough room for an fbink -Z bar, small horizontal margins, and a font size based on what 6pt looked like @ 265dpi
./fbink -q -b -O -t regular=./fonts/droid/DroidSansMono.ttf,top=$((viewHeight / 2 + FONTH * 2 + FONTH / 2)),left=$((viewWidth / 60)),right=$((viewWidth / 60)),px=$((viewHeight / 64)) "${crashLog}" ./fbink -q -b -O -t regular=./fonts/droid/DroidSansMono.ttf,top=$((viewHeight / 2 + FONTH * 2 + FONTH / 2)),left=$((viewWidth / 60)),right=$((viewWidth / 60)),px=$((viewHeight / 64)) -- "${crashLog}"
# So far, we hadn't triggered an actual screen refresh, do that now, to make sure everything is bundled in a single flashing refresh. # So far, we hadn't triggered an actual screen refresh, do that now, to make sure everything is bundled in a single flashing refresh.
./fbink -q -f -s ./fbink -q -f -s
# Cue a lemming's faceplant sound effect! # Cue a lemming's faceplant sound effect!

@ -5,9 +5,9 @@ if [ "$1" = "on" ]; then
wmiconfig -i wlan0 --wlan enable wmiconfig -i wlan0 --wlan enable
wmiconfig -i wlan0 --setreassocmode 0 wmiconfig -i wlan0 --setreassocmode 0
wmiconfig -i wlan0 --power maxperf wmiconfig -i wlan0 --power maxperf
echo "WiFi Enabled" echo "Wi-Fi Enabled"
else else
wmiconfig -i wlan0 --abortscan wmiconfig -i wlan0 --abortscan
wmiconfig -i wlan0 --wlan disable wmiconfig -i wlan0 --wlan disable
echo "Wifi Disabled" echo "Wi-Fi Disabled"
fi fi

@ -2,7 +2,7 @@
set -x set -x
# disable WiFi # disable Wi-Fi
./set-wifi.sh off ./set-wifi.sh off
# enter sleep, disabling all devices except CPU # enter sleep, disabling all devices except CPU

@ -203,6 +203,10 @@ Do you want to continue? ]]), driver),
end end
function CalibreWireless:connect() function CalibreWireless:connect()
if NetworkMgr:willRerunWhenConnected(function() self:connect() end) then
return
end
self.connect_message = false self.connect_message = false
local host, port local host, port
if G_reader_settings:hasNot("calibre_wireless_url") then if G_reader_settings:hasNot("calibre_wireless_url") then
@ -231,8 +235,6 @@ function CalibreWireless:connect()
else else
self:setInboxDir(host, port) self:setInboxDir(host, port)
end end
elseif not NetworkMgr:isConnected() then
NetworkMgr:promptWifiOn()
else else
logger.info("cannot connect to calibre server") logger.info("cannot connect to calibre server")
UIManager:show(InfoMessage:new{ UIManager:show(InfoMessage:new{

@ -347,10 +347,10 @@ For more information, please visit https://github.com/koreader/koreader/wiki/Eve
end end
function EvernoteExporter:login() function EvernoteExporter:login()
if not NetworkMgr:isOnline() then if NetworkMgr:willRerunWhenOnline(function() self:login() end) then
NetworkMgr:promptWifiOn()
return return
end end
self.login_dialog = LoginDialog:new{ self.login_dialog = LoginDialog:new{
title = self.login_title, title = self.login_title,
username = self.evernote_username or "", username = self.evernote_username or "",
@ -410,7 +410,7 @@ function EvernoteExporter:doLogin(username, password)
} }
self.evernote_username = username self.evernote_username = username
local ok, token = pcall(oauth.getToken, oauth) local ok, token = pcall(oauth.getToken, oauth)
-- prompt users to turn on Wifi if network is unreachable -- prompt users to turn on Wi-Fi if network is unreachable
if not ok and token then if not ok and token then
UIManager:show(InfoMessage:new{ UIManager:show(InfoMessage:new{
text = _("An error occurred while logging in:") .. "\n" .. token, text = _("An error occurred while logging in:") .. "\n" .. token,
@ -425,7 +425,8 @@ function EvernoteExporter:doLogin(username, password)
local guid local guid
ok, guid = pcall(self.getExportNotebook, self, client) ok, guid = pcall(self.getExportNotebook, self, client)
if not ok and guid and guid:find("Transport not open") then if not ok and guid and guid:find("Transport not open") then
NetworkMgr:promptWifiOn() --- @note: No recursive callback because it feels fishy here...
NetworkMgr:beforeWifiAction()
return return
elseif not ok and guid then elseif not ok and guid then
UIManager:show(InfoMessage:new{ UIManager:show(InfoMessage:new{
@ -589,7 +590,7 @@ function EvernoteExporter:exportClippings(clippings)
end end
-- check if booknotes are exported in this notebook -- check if booknotes are exported in this notebook
-- so that booknotes will still be exported after switching user account -- so that booknotes will still be exported after switching user account
--Don't respect exported_stamp on txt export since it isn't possible to delete(update) prior clippings. -- Don't respect exported_stamp on txt export since it isn't possible to delete(update) prior clippings.
if booknotes.exported[exported_stamp] ~= true or self.txt_export or self.json_export then if booknotes.exported[exported_stamp] ~= true or self.txt_export or self.json_export then
local ok, err local ok, err
if self.html_export then if self.html_export then
@ -603,9 +604,10 @@ function EvernoteExporter:exportClippings(clippings)
else else
ok, err = pcall(self.exportBooknotesToEvernote, self, client, title, booknotes) ok, err = pcall(self.exportBooknotesToEvernote, self, client, title, booknotes)
end end
-- error reporting -- Error reporting
if not ok and err and err:find("Transport not open") then if not ok and err and err:find("Transport not open") then
NetworkMgr:promptWifiOn() --- @note: No recursive callback because it feels fishy here...
NetworkMgr:beforeWifiAction()
return return
elseif not ok and err then elseif not ok and err then
logger.dbg("Error while exporting book", title, err) logger.dbg("Error while exporting book", title, err)

@ -170,16 +170,16 @@ end
-- search_type = author - serch book by author -- search_type = author - serch book by author
-- search_type = title - search book by title -- search_type = title - search book by title
function Goodreads:search(search_type) function Goodreads:search(search_type)
if NetworkMgr:willRerunWhenOnline(function() self:search(search_type) end) then
return
end
local title_header local title_header
local hint local hint
local search_input local search_input
local text_input local text_input
local info local info
local result local result
if not NetworkMgr:isOnline() then
NetworkMgr:promptWifiOn()
return
end
if search_type == "all" then if search_type == "all" then
title_header = _("Search all books in Goodreads") title_header = _("Search all books in Goodreads")
hint = _("Title, author or ISBN") hint = _("Title, author or ISBN")

@ -295,10 +295,10 @@ function KOSync:setWhisperBackward(strategy)
end end
function KOSync:login() function KOSync:login()
if not NetworkMgr:isOnline() then if NetworkMgr:willRerunWhenOnline(function() self:login() end) then
NetworkMgr:promptWifiOn()
return return
end end
self.login_dialog = LoginDialog:new{ self.login_dialog = LoginDialog:new{
title = self.title, title = self.title,
username = self.kosync_username or "", username = self.kosync_username or "",

@ -22,7 +22,6 @@ local NewsDownloader = WidgetContainer:new{
} }
local initialized = false local initialized = false
local wifi_enabled_before_action = true
local feed_config_file_name = "feed_config.lua" local feed_config_file_name = "feed_config.lua"
local news_downloader_config_file = "news_downloader_settings.lua" local news_downloader_config_file = "news_downloader_settings.lua"
local news_downloader_settings local news_downloader_settings
@ -59,13 +58,6 @@ local function getFeedLink(possible_link)
end end
end end
--- @todo Implement as NetworkMgr:afterWifiAction with configuration options.
function NewsDownloader:afterWifiAction()
if not wifi_enabled_before_action then
NetworkMgr:promptWifiOff()
end
end
function NewsDownloader:init() function NewsDownloader:init()
self.ui.menu:registerToMainMenu(self) self.ui.menu:registerToMainMenu(self)
end end
@ -79,12 +71,7 @@ function NewsDownloader:addToMainMenu(menu_items)
text = _("Download news"), text = _("Download news"),
keep_menu_open = true, keep_menu_open = true,
callback = function() callback = function()
if not NetworkMgr:isOnline() then NetworkMgr:runWhenOnline(function() self:loadConfigAndProcessFeedsWithUI() end)
wifi_enabled_before_action = false
NetworkMgr:beforeWifiAction(self.loadConfigAndProcessFeedsWithUI)
else
self:loadConfigAndProcessFeedsWithUI()
end
end, end,
}, },
{ {
@ -222,7 +209,7 @@ function NewsDownloader:loadConfigAndProcessFeeds()
end end
UI:info(T(_("Downloading news finished. Could not process some feeds. Unsupported format in: %1"), unsupported_urls)) UI:info(T(_("Downloading news finished. Could not process some feeds. Unsupported format in: %1"), unsupported_urls))
end end
NewsDownloader:afterWifiAction() NetworkMgr:afterWifiAction()
end end
function NewsDownloader:loadConfigAndProcessFeedsWithUI() function NewsDownloader:loadConfigAndProcessFeedsWithUI()

@ -21,7 +21,6 @@ local Send2Ebook = WidgetContainer:new{
} }
local initialized = false local initialized = false
local wifi_enabled_before_action = true
local send2ebook_config_file = "send2ebook_settings.lua" local send2ebook_config_file = "send2ebook_settings.lua"
local config_key_custom_dl_dir = "custom_dl_dir"; local config_key_custom_dl_dir = "custom_dl_dir";
local default_download_dir_name = "send2ebook" local default_download_dir_name = "send2ebook"
@ -45,13 +44,6 @@ function Send2Ebook:downloadFileAndRemove(connection_url, remote_path, local_dow
end end
end end
--- @todo Implement as NetworkMgr:afterWifiAction with configuration options.
function Send2Ebook:afterWifiAction()
if not wifi_enabled_before_action then
NetworkMgr:promptWifiOff()
end
end
function Send2Ebook:init() function Send2Ebook:init()
self.ui.menu:registerToMainMenu(self) self.ui.menu:registerToMainMenu(self)
end end
@ -65,12 +57,10 @@ function Send2Ebook:addToMainMenu(menu_items)
text = _("Download and remove from server"), text = _("Download and remove from server"),
keep_menu_open = true, keep_menu_open = true,
callback = function() callback = function()
if not NetworkMgr:isOnline() then local connect_callback = function()
wifi_enabled_before_action = false self:process()
NetworkMgr:beforeWifiAction(self.process) end
else NetworkMgr:runWhenOnline(connect_callback)
self:process()
end
end, end,
}, },
{ {
@ -171,7 +161,7 @@ function Send2Ebook:process()
end end
end end
UIManager:show(info) UIManager:show(info)
Send2Ebook:afterWifiAction() NetworkMgr:afterWifiAction()
end end
function Send2Ebook:removeReadActicles() function Send2Ebook:removeReadActicles()

@ -34,7 +34,7 @@ local function currentTime()
return _("Time synchronized.") return _("Time synchronized.")
end end
local function execute() local function syncNTP()
local info = InfoMessage:new{ local info = InfoMessage:new{
text = _("Synchronizing time. This may take several seconds.") text = _("Synchronizing time. This may take several seconds.")
} }
@ -58,11 +58,7 @@ local menuItem = {
text = _("Synchronize time"), text = _("Synchronize time"),
keep_menu_open = true, keep_menu_open = true,
callback = function() callback = function()
if NetworkMgr:isOnline() then NetworkMgr:runWhenOnline(function() syncNTP() end)
execute()
else
NetworkMgr:promptWifiOn()
end
end end
} }

@ -112,15 +112,14 @@ function Wallabag:addToMainMenu(menu_items)
{ {
text = _("Delete finished articles remotely"), text = _("Delete finished articles remotely"),
callback = function() callback = function()
if not NetworkMgr:isOnline() then local connect_callback = function()
NetworkMgr:promptWifiOn() local num_deleted = self:processLocalFiles("manual")
return UIManager:show(InfoMessage:new{
text = T(_("Articles processed.\nDeleted: %1"), num_deleted)
})
self:refreshCurrentDirIfNeeded()
end end
local num_deleted = self:processLocalFiles("manual") NetworkMgr:runWhenOnline(connect_callback)
UIManager:show(InfoMessage:new{
text = T(_("Articles processed.\nDeleted: %1"), num_deleted)
})
self:refreshCurrentDirIfNeeded()
end, end,
enabled_func = function() enabled_func = function()
return self.is_delete_finished or self.is_delete_read return self.is_delete_finished or self.is_delete_read
@ -1078,12 +1077,11 @@ function Wallabag:onAddWallabagArticle(article_url)
end end
function Wallabag:onSynchronizeWallabag() function Wallabag:onSynchronizeWallabag()
if not NetworkMgr:isOnline() then local connect_callback = function()
NetworkMgr:promptWifiOn() self:synchronize()
return self:refreshCurrentDirIfNeeded()
end end
self:synchronize() NetworkMgr:runWhenOnline(connect_callback)
self:refreshCurrentDirIfNeeded()
-- stop propagation -- stop propagation
return true return true

@ -41,15 +41,14 @@ function ZSync:addToMainMenu(menu_items)
end, end,
callback = function() callback = function()
local NetworkMgr = require("ui/network/manager") local NetworkMgr = require("ui/network/manager")
if not NetworkMgr:isOnline() then local connect_callback = function()
NetworkMgr:promptWifiOn() if not self.filemq_server then
return self:publish()
end else
if not self.filemq_server then self:unpublish()
self:publish() end
else
self:unpublish()
end end
NetworkMgr:runWhenOnline(connect_callback)
end end
}, },
{ {
@ -63,15 +62,14 @@ function ZSync:addToMainMenu(menu_items)
end, end,
callback = function() callback = function()
local NetworkMgr = require("ui/network/manager") local NetworkMgr = require("ui/network/manager")
if not NetworkMgr:isOnline() then local connect_callback = function()
NetworkMgr:promptWifiOn() if not self.filemq_client then
return self:subscribe()
end else
if not self.filemq_client then self:unsubscribe()
self:subscribe() end
else
self:unsubscribe()
end end
NetworkMgr:runWhenOnline(connect_callback)
end end
} }
} }

@ -12,7 +12,7 @@ describe("NetworkSetting module", function()
assert.is.falsy(ns.connected_item) assert.is.falsy(ns.connected_item)
end) end)
it("should call connect_callback after disconnect", function() it("should NOT call connect_callback after disconnect", function()
stub(NetworkMgr, "disconnectNetwork") stub(NetworkMgr, "disconnectNetwork")
stub(NetworkMgr, "releaseIP") stub(NetworkMgr, "releaseIP")
@ -33,6 +33,33 @@ describe("NetworkSetting module", function()
connect_callback = function() called = true end connect_callback = function() called = true end
} }
ns.connected_item:disconnect() ns.connected_item:disconnect()
assert.falsy(called)
NetworkMgr.disconnectNetwork:revert()
NetworkMgr.releaseIP:revert()
end)
it("should call disconnect_callback after disconnect", function()
stub(NetworkMgr, "disconnectNetwork")
stub(NetworkMgr, "releaseIP")
UIManager:quit()
local called = false
local network_list = {
{
ssid = "foo",
signal_level = -58,
flags = "[WPA2-PSK-CCMP][ESS]",
signal_quality = 84,
password = "123abc",
connected = true,
},
}
local ns = NetworkSetting:new{
network_list = network_list,
disconnect_callback = function() called = true end
}
ns.connected_item:disconnect()
assert.truthy(called) assert.truthy(called)
NetworkMgr.disconnectNetwork:revert() NetworkMgr.disconnectNetwork:revert()

Loading…
Cancel
Save