mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
[feat, Kobo] Autoshutdown (#5335)
The methods used here will likely work on most embedded devices, which is why I put them in their own WakeupMgr interface/scheduler module, separate from Kobo. See https://www.mobileread.com/forums/showthread.php?p=3886403#post3886403 for more context. Fixes #3806.
This commit is contained in:
@@ -3,4 +3,5 @@ return {
|
||||
name = "autosuspend",
|
||||
fullname = _("Auto suspend"),
|
||||
description = _([[Suspends the device after a period of inactivity.]]),
|
||||
sorting_hint = "device",
|
||||
}
|
||||
|
||||
@@ -11,10 +11,15 @@ local UIManager = require("ui/uimanager")
|
||||
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
||||
local logger = require("logger")
|
||||
local _ = require("gettext")
|
||||
local T = require("ffi/util").template
|
||||
|
||||
local AutoSuspend = {
|
||||
local default_autoshutdown_timeout_seconds = 3*24*60*60
|
||||
|
||||
local AutoSuspend = WidgetContainer:new{
|
||||
name = "autosuspend",
|
||||
is_doc_only = false,
|
||||
autoshutdown_sec = G_reader_settings:readSetting("autoshutdown_timeout_seconds") or default_autoshutdown_timeout_seconds,
|
||||
settings = LuaSettings:open(DataStorage:getSettingsDir() .. "/koboautosuspend.lua"),
|
||||
settings_id = 0,
|
||||
last_action_sec = os.time(),
|
||||
}
|
||||
|
||||
@@ -43,54 +48,65 @@ function AutoSuspend:_enabled()
|
||||
return self.auto_suspend_sec > 0
|
||||
end
|
||||
|
||||
function AutoSuspend:_schedule(settings_id)
|
||||
function AutoSuspend:_enabledShutdown()
|
||||
return Device:canPowerOff() and self.autoshutdown_sec > 0
|
||||
end
|
||||
|
||||
function AutoSuspend:_schedule()
|
||||
if not self:_enabled() then
|
||||
logger.dbg("AutoSuspend:_schedule is disabled")
|
||||
return
|
||||
end
|
||||
if self.settings_id ~= settings_id then
|
||||
logger.dbg("AutoSuspend:_schedule registered settings_id ",
|
||||
settings_id,
|
||||
" does not equal to current one ",
|
||||
self.settings_id)
|
||||
return
|
||||
end
|
||||
|
||||
local delay
|
||||
local delay_suspend, delay_shutdown
|
||||
|
||||
if PluginShare.pause_auto_suspend then
|
||||
delay = self.auto_suspend_sec
|
||||
delay_suspend = self.auto_suspend_sec
|
||||
delay_shutdown = self.autoshutdown_sec
|
||||
else
|
||||
delay = self.last_action_sec + self.auto_suspend_sec - os.time()
|
||||
delay_suspend = self.last_action_sec + self.auto_suspend_sec - os.time()
|
||||
delay_shutdown = self.last_action_sec + self.autoshutdown_sec - os.time()
|
||||
end
|
||||
|
||||
if delay <= 0 then
|
||||
if delay_suspend <= 0 then
|
||||
logger.dbg("AutoSuspend: will suspend the device")
|
||||
UIManager:suspend()
|
||||
elseif delay_shutdown <= 0 then
|
||||
logger.dbg("AutoSuspend: initiating shutdown")
|
||||
UIManager:poweroff_action()
|
||||
else
|
||||
logger.dbg("AutoSuspend: schedule at ", os.time() + delay)
|
||||
UIManager:scheduleIn(delay, function() self:_schedule(settings_id) end)
|
||||
if self:_enabled() then
|
||||
logger.dbg("AutoSuspend: schedule suspend at ", os.time() + delay_suspend)
|
||||
UIManager:scheduleIn(delay_suspend, self._schedule, self)
|
||||
end
|
||||
if self:_enabledShutdown() then
|
||||
logger.dbg("AutoSuspend: schedule shutdown at ", os.time() + delay_shutdown)
|
||||
UIManager:scheduleIn(delay_shutdown, self._schedule, self)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AutoSuspend:_deprecateLastTask()
|
||||
self.settings_id = self.settings_id + 1
|
||||
logger.dbg("AutoSuspend: deprecateLastTask ", self.settings_id)
|
||||
function AutoSuspend:_unschedule()
|
||||
logger.dbg("AutoSuspend: unschedule")
|
||||
UIManager:unschedule(self._schedule)
|
||||
end
|
||||
|
||||
function AutoSuspend:_start()
|
||||
if self:_enabled() then
|
||||
if self:_enabled() or self:_enabledShutdown() then
|
||||
logger.dbg("AutoSuspend: start at ", os.time())
|
||||
self.last_action_sec = os.time()
|
||||
self:_schedule(self.settings_id)
|
||||
self:_schedule()
|
||||
end
|
||||
end
|
||||
|
||||
function AutoSuspend:init()
|
||||
UIManager.event_hook:registerWidget("InputEvent", self)
|
||||
self.auto_suspend_sec = self:_readTimeoutSec()
|
||||
self:_deprecateLastTask()
|
||||
self:_unschedule()
|
||||
self:_start()
|
||||
-- self.ui is nil in the testsuite
|
||||
if not self.ui or not self.ui.menu then return end
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
end
|
||||
|
||||
function AutoSuspend:onInputEvent()
|
||||
@@ -98,11 +114,14 @@ function AutoSuspend:onInputEvent()
|
||||
self.last_action_sec = os.time()
|
||||
end
|
||||
|
||||
-- We do not want auto suspend procedure to waste battery during suspend. So let's unschedule it
|
||||
-- when suspending and restart it after resume.
|
||||
function AutoSuspend:onSuspend()
|
||||
logger.dbg("AutoSuspend: onSuspend")
|
||||
self:_deprecateLastTask()
|
||||
-- We do not want auto suspend procedure to waste battery during suspend. So let's unschedule it
|
||||
-- when suspending and restart it after resume.
|
||||
self:_unschedule()
|
||||
if self:_enabledShutdown() and Device.wakeup_mgr then
|
||||
Device.wakeup_mgr:addTask(self.autoshutdown_sec, UIManager.poweroff_action)
|
||||
end
|
||||
end
|
||||
|
||||
function AutoSuspend:onResume()
|
||||
@@ -110,23 +129,9 @@ function AutoSuspend:onResume()
|
||||
self:_start()
|
||||
end
|
||||
|
||||
AutoSuspend:init()
|
||||
|
||||
local AutoSuspendWidget = WidgetContainer:new{
|
||||
name = "autosuspend",
|
||||
}
|
||||
|
||||
function AutoSuspendWidget:addToMainMenu(menu_items)
|
||||
function AutoSuspend:addToMainMenu(menu_items)
|
||||
menu_items.autosuspend = {
|
||||
text = _("Autosuspend timeout"),
|
||||
-- This won't ever be registered if the plugin is disabled ;).
|
||||
--[[
|
||||
enabled_func = function()
|
||||
-- NOTE: Pilfered from frontend/pluginloader.lua
|
||||
local plugins_disabled = G_reader_settings:readSetting("plugins_disabled") or {}
|
||||
return plugins_disabled["autosuspend"] ~= true
|
||||
end,
|
||||
--]]
|
||||
callback = function()
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local Screen = Device.screen
|
||||
@@ -141,11 +146,53 @@ function AutoSuspendWidget:addToMainMenu(menu_items)
|
||||
ok_text = _("Set timeout"),
|
||||
title_text = _("Timeout in minutes"),
|
||||
callback = function(autosuspend_spin)
|
||||
G_reader_settings:saveSetting("auto_suspend_timeout_seconds", autosuspend_spin.value * 60)
|
||||
-- NOTE: Will only take effect after a restart, as we don't have a method to set this live...
|
||||
local autosuspend_timeout_seconds = autosuspend_spin.value * 60
|
||||
self.auto_suspend_sec = autosuspend_timeout_seconds
|
||||
G_reader_settings:saveSetting("auto_suspend_timeout_seconds", autosuspend_timeout_seconds)
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("This will take effect on next restart."),
|
||||
text = T(_("The system will automatically suspend after %1 minutes of inactivity."),
|
||||
string.format("%.2f", autosuspend_timeout_seconds/60)),
|
||||
timeout = 3,
|
||||
})
|
||||
self:_unschedule()
|
||||
self:_start()
|
||||
end
|
||||
}
|
||||
UIManager:show(autosuspend_spin)
|
||||
end,
|
||||
}
|
||||
if not (Device:canPowerOff() or Device:isEmulator()) then return end
|
||||
menu_items.autoshutdown = {
|
||||
text = _("Autoshutdown timeout"),
|
||||
callback = function()
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local Screen = Device.screen
|
||||
local SpinWidget = require("ui/widget/spinwidget")
|
||||
local curr_items = G_reader_settings:readSetting("autoshutdown_timeout_seconds") or default_autoshutdown_timeout_seconds
|
||||
local autosuspend_spin = SpinWidget:new {
|
||||
width = Screen:getWidth() * 0.6,
|
||||
value = curr_items / 60 / 60,
|
||||
-- About a minute, good for testing and battery life fanatics.
|
||||
-- Just high enough to avoid an instant shutdown death scenario.
|
||||
value_min = 0.017,
|
||||
-- More than three weeks seems a bit excessive if you want to enable authoshutdown,
|
||||
-- even if the battery can last up to three months.
|
||||
value_max = 28*24,
|
||||
value_hold_step = 24,
|
||||
precision = "%.2f",
|
||||
ok_text = _("Set timeout"),
|
||||
title_text = _("Timeout in hours"),
|
||||
callback = function(autosuspend_spin)
|
||||
local autoshutdown_timeout_seconds = math.floor(autosuspend_spin.value * 60*60)
|
||||
self.autoshutdown_timeout_seconds = autoshutdown_timeout_seconds
|
||||
G_reader_settings:saveSetting("autoshutdown_timeout_seconds", autoshutdown_timeout_seconds)
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = T(_("The system will automatically shut down after %1 hours of inactivity."),
|
||||
string.format("%.2f", autoshutdown_timeout_seconds/60/60)),
|
||||
timeout = 3,
|
||||
})
|
||||
self:_unschedule()
|
||||
self:_start()
|
||||
end
|
||||
}
|
||||
UIManager:show(autosuspend_spin)
|
||||
@@ -153,22 +200,4 @@ function AutoSuspendWidget:addToMainMenu(menu_items)
|
||||
}
|
||||
end
|
||||
|
||||
function AutoSuspendWidget:init()
|
||||
-- self.ui is nil in the testsuite
|
||||
if not self.ui or not self.ui.menu then return end
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
end
|
||||
|
||||
function AutoSuspendWidget:onInputEvent()
|
||||
AutoSuspend:onInputEvent()
|
||||
end
|
||||
|
||||
function AutoSuspendWidget:onSuspend()
|
||||
AutoSuspend:onSuspend()
|
||||
end
|
||||
|
||||
function AutoSuspendWidget:onResume()
|
||||
AutoSuspend:onResume()
|
||||
end
|
||||
|
||||
return AutoSuspendWidget
|
||||
return AutoSuspend
|
||||
|
||||
Reference in New Issue
Block a user