diff --git a/frontend/apps/reader/modules/readercoptlistener.lua b/frontend/apps/reader/modules/readercoptlistener.lua index 25d6a4cff..04f80a549 100644 --- a/frontend/apps/reader/modules/readercoptlistener.lua +++ b/frontend/apps/reader/modules/readercoptlistener.lua @@ -165,10 +165,6 @@ function ReaderCoptListener:onResume() self:headerRefresh() end -function ReaderCoptListener:onLeaveStandby() - self:headerRefresh() -end - function ReaderCoptListener:onOutOfScreenSaver() if not self._delayed_screensaver then return @@ -181,7 +177,6 @@ end -- Unschedule on these events ReaderCoptListener.onCloseDocument = ReaderCoptListener.unscheduleHeaderRefresh ReaderCoptListener.onSuspend = ReaderCoptListener.unscheduleHeaderRefresh -ReaderCoptListener.onEnterStandby = ReaderCoptListener.unscheduleHeaderRefresh function ReaderCoptListener:setAndSave(setting, property, value) self.ui.document._document:setIntProperty(property, value) diff --git a/frontend/apps/reader/modules/readerfooter.lua b/frontend/apps/reader/modules/readerfooter.lua index 02e70f8a2..fc36af187 100644 --- a/frontend/apps/reader/modules/readerfooter.lua +++ b/frontend/apps/reader/modules/readerfooter.lua @@ -2471,21 +2471,12 @@ function ReaderFooter:onOutOfScreenSaver() self:rescheduleFooterAutoRefreshIfNeeded() end -function ReaderFooter:onLeaveStandby() - self:maybeUpdateFooter() - self:rescheduleFooterAutoRefreshIfNeeded() -end - function ReaderFooter:onSuspend() self:unscheduleFooterAutoRefresh() -- Reset the initial marker self.progress_bar.inital_percentage = nil end -function ReaderFooter:onEnterStandby() - self:unscheduleFooterAutoRefresh() -end - function ReaderFooter:onCloseDocument() self:unscheduleFooterAutoRefresh() end diff --git a/frontend/ui/uimanager.lua b/frontend/ui/uimanager.lua index f0eaf7bbb..02de899fc 100644 --- a/frontend/ui/uimanager.lua +++ b/frontend/ui/uimanager.lua @@ -243,6 +243,16 @@ function UIManager:close(widget, refreshtype, refreshregion, refreshdither) end end +--- Shift the execution times of all scheduled tasks. +-- UIManager uses CLOCK_MONOTONIC (which doesn't tick during standby), so shifting the execution +-- time by a negative value will lead to an execution at the expected time. +-- @param time if positive execute the tasks later, if negative they should be executed earlier +function UIManager:shiftScheduledTasksBy(shift_time) + for i, v in ipairs(self._task_queue) do + v.time = v.time + shift_time + end +end + -- Schedule an execution task; task queue is in descending order function UIManager:schedule(sched_time, action, ...) local lo, hi = 1, #self._task_queue diff --git a/plugins/autodim.koplugin/main.lua b/plugins/autodim.koplugin/main.lua index a2b71a02f..ab0461577 100644 --- a/plugins/autodim.koplugin/main.lua +++ b/plugins/autodim.koplugin/main.lua @@ -212,44 +212,14 @@ function AutoDim:_onResume() self:_schedule_autodim_task() end -function AutoDim:_onEnterStandby() - self:_unschedule_autodim_task() - -- don't unschedule ramp task, as this is done in onLeaveStandby if necessary -end - -function AutoDim:_onLeaveStandby() - if self.isCurrentlyDimming then - if self.last_ramp_scheduling_time then - -- we are during the ramp down - local now = UIManager:getElapsedTimeSinceBoot() - local next_ramp_time_s = self.last_ramp_scheduling_time + time.s(self.autodim_step_time_s) - now - self:_unschedule_ramp_task() -- self.last_ramp_scheduling_time gets deleted with this call - self.isCurrentlyDimming = true -- as this gets deleted by `_unschedule_ramp_task()` - if next_ramp_time_s <= 0 then -- only happens, when standby is ended by a scheduled ramp_task() - self:ramp_task() - else - self:_schedule_ramp_task(time.to_s(next_ramp_time_s)) - end - else - self:_unschedule_ramp_task() - end - else - self:autodim_task() -- check times and reschedule autodim_task if necessary - end -end - function AutoDim:setEventHandlers() self.onResume = self._onResume self.onSuspend = self._onSuspend - self.onEnterStandby = self._onEnterStandby - self.onLeaveStandby = self._onLeaveStandby end function AutoDim:clearEventHandlers() self.onResume = nil self.onSuspend = nil - self.onEnterStandby = nil - self.onLeaveStandby = nil end function AutoDim:onFrontlightTurnedOff() diff --git a/plugins/autosuspend.koplugin/main.lua b/plugins/autosuspend.koplugin/main.lua index 8e618720b..75440b14d 100644 --- a/plugins/autosuspend.koplugin/main.lua +++ b/plugins/autosuspend.koplugin/main.lua @@ -5,7 +5,6 @@ if not Device:canSuspend() then return { disabled = true, } end -local Event = require("ui/event") local Math = require("optmath") local NetworkMgr = require("ui/network/manager") local PluginShare = require("pluginshare") @@ -34,8 +33,6 @@ local AutoSuspend = WidgetContainer:extend{ task = nil, kindle_task = nil, standby_task = nil, - leave_standby_task = nil, - wrapped_leave_standby_task = nil, going_to_suspend = nil, } @@ -109,10 +106,10 @@ function AutoSuspend:_start() end end -function AutoSuspend:_start_standby() +function AutoSuspend:_start_standby(sleep_in) if self:_enabledStandby() then logger.dbg("AutoSuspend: start standby timer at", time.format_time(self.last_action_time)) - self:_schedule_standby() + self:_schedule_standby(sleep_in) end end @@ -201,14 +198,6 @@ function AutoSuspend:init() self.standby_task = function() self:_schedule_standby() end - self.leave_standby_task = function() - -- Only if we're not already entering suspend... - if self.going_to_suspend then - return - end - - UIManager:broadcastEvent(Event:new("LeaveStandby")) - end -- Make sure we only have an AllowStandby handler when we actually want one... self:toggleStandbyHandler(self:_enabledStandby()) @@ -235,7 +224,6 @@ function AutoSuspend:onCloseWidget() self:_unschedule_standby() self.standby_task = nil - self.leave_standby_task = nil end function AutoSuspend:onInputEvent() @@ -252,17 +240,13 @@ function AutoSuspend:_unschedule_standby() self.is_standby_scheduled = false end - - -- Make sure we don't trigger a ghost LeaveStandby event... - if self.leave_standby_task then - logger.dbg("AutoSuspend: unschedule leave standby task") - UIManager:unschedule(self.leave_standby_task) - end end -function AutoSuspend:_schedule_standby() +function AutoSuspend:_schedule_standby(sleep_in) + sleep_in = sleep_in or self.auto_standby_timeout_seconds + -- Start the long list of conditions in which we do *NOT* want to go into standby ;). - if not Device:canStandby() then + if not Device:canStandby() or self.going_to_suspend then return end @@ -292,7 +276,7 @@ function AutoSuspend:_schedule_standby() standby_delay_seconds = self.auto_standby_timeout_seconds else local now = UIManager:getElapsedTimeSinceBoot() - standby_delay_seconds = self.auto_standby_timeout_seconds - time.to_number(now - self.last_action_time) + standby_delay_seconds = sleep_in - time.to_number(now - self.last_action_time) -- If we blow past the deadline on the first call of a scheduling cycle, -- make sure we don't go straight to allowStandby, as we haven't called preventStandby yet... @@ -302,7 +286,7 @@ function AutoSuspend:_schedule_standby() -- or if the only input events we consumed did not trigger an InputEvent event (woken up by gyro events), -- meaning self.last_action_time is further in the past than it ought to. -- Delay by the full amount to avoid further bad scheduling interactions. - standby_delay_seconds = self.auto_standby_timeout_seconds + standby_delay_seconds = sleep_in end end @@ -360,8 +344,7 @@ function AutoSuspend:onSuspend() UIManager:preventStandby() end - -- And make sure onLeaveStandby, which will come *after* us if we suspended *during* standby, - -- won't re-schedule stuff right before entering suspend... + -- Make sure that we don't re-schedule standby *after* us if we suspended *during* standby, self.going_to_suspend = true end @@ -386,20 +369,6 @@ function AutoSuspend:onResume() self:_start_standby() end -function AutoSuspend:onLeaveStandby() - logger.dbg("AutoSuspend: onLeaveStandby") - -- Unschedule suspend and shutdown, as the realtime clock has ticked - self:_unschedule() - -- Reschedule suspend and shutdown (we'll recompute the delay based on the last user input, *not* the current time). - -- i.e., the goal is to behave as if we'd never unscheduled it, making sure we do *NOT* reset the delay to the full timeout. - self:_start() - -- Assuming _start didn't send us straight to onSuspend (i.e., we were woken from standby by the scheduled suspend task!)... - if not self.going_to_suspend then - -- Reschedule standby, too (we're guaranteed that no standby task is currently scheduled, hence the lack of unscheduling). - self:_start_standby() - end -end - function AutoSuspend:onUnexpectedWakeupLimit() logger.dbg("AutoSuspend: onUnexpectedWakeupLimit") -- Should be unnecessary, because we should *always* follow onSuspend, which already does this... @@ -649,7 +618,6 @@ function AutoSuspend:AllowStandbyHandler() end if wake_in >= 3 then -- don't go into standby, if scheduled wakeup is in less than 3 secs - UIManager:broadcastEvent(Event:new("EnterStandby")) logger.dbg("AutoSuspend: entering standby with a wakeup alarm in", wake_in, "s") -- This obviously needs a matching implementation in Device, the canonical one being Kobo. @@ -657,29 +625,28 @@ function AutoSuspend:AllowStandbyHandler() logger.dbg("AutoSuspend: left standby after", time.format_time(Device.last_standby_time), "s") - -- We delay the LeaveStandby event (our onLeaveStandby handler is responsible for rescheduling everything properly), - -- to make sure UIManager will consume the input events that woke us up first - -- (in case we were woken up by user input, as opposed to an rtc wake alarm)! - -- (This ensures we'll use an up to date last_action_time, and that it only ever gets updated from *user* input). - -- NOTE: While UIManager consumes scheduled tasks before input events, we do *NOT* have to rely on tickAfterNext, + -- NOTE: UIManager consumes scheduled tasks before input events, -- solely because of where we run inside an UI frame (via UIManager:_standbyTransition): -- we're neither a scheduled task nor an input event, we run *between* scheduled tasks and input polling. -- That means we go straight to input polling when returning, *without* a trip through the task queue -- (c.f., UIManager:_checkTasks in UIManager:handleInput). - UIManager:nextTick(self.leave_standby_task) + + UIManager:shiftScheduledTasksBy( - Device.last_standby_time) -- correct scheduled times by last_standby_time -- Since we go straight to input polling, and that our time spent in standby won't have affected the already computed -- input polling deadline (because MONOTONIC doesn't tick during standby/suspend), -- tweak said deadline to make sure poll will return immediately, so we get a chance to run through the task queue ASAP. - -- This ensures we get a LeaveStandby event in a timely fashion, - -- even when there isn't actually any user input happening (e.g., woken up by the rtc alarm). -- This shouldn't prevent us from actually consuming any pending input events first, -- because if we were woken up by user input, those events should already be in the evdev queue... UIManager:consumeInputEarlyAfterPM(true) + + -- When we exit this method, we are sure that the input polling deadline is zero (consumeInputEarly). + -- UIManager will check newly scheduled tasks before going to input polling again (with a new deadline). + self:_start_standby() -- Schedule the next standby check in the future. else - if not self.going_to_suspend then - self:_start_standby() - end + -- When we exit this method, we are sure that the input polling deadline is approximately `wake_in`. + -- So it is safe to schedule another task a bit later. + self:_start_standby(wake_in + 0.1) -- Schedule the next standby check 0.1 seconds after the next calculated wakeup time. end end diff --git a/plugins/autoturn.koplugin/main.lua b/plugins/autoturn.koplugin/main.lua index e17b8e16f..4801aab33 100644 --- a/plugins/autoturn.koplugin/main.lua +++ b/plugins/autoturn.koplugin/main.lua @@ -1,4 +1,3 @@ -local Device = require("device") local Event = require("ui/event") local PluginShare = require("pluginshare") local UIManager = require("ui/uimanager") @@ -29,14 +28,14 @@ function AutoTurn:_schedule() return end - local delay = self.last_action_time + time.s(self.autoturn_sec) - UIManager:getTime() + local delay = self.last_action_time + time.s(self.autoturn_sec) - UIManager:getElapsedTimeSinceBoot() if delay <= 0 then local top_wg = UIManager:getTopmostVisibleWidget() or {} if top_wg.name == "ReaderUI" then logger.dbg("AutoTurn: go to next page") self.ui:handleEvent(Event:new("GotoViewRel", self.autoturn_distance)) - self.last_action_time = UIManager:getTime() + self.last_action_time = UIManager:getElapsedTimeSinceBoot() end logger.dbg("AutoTurn: schedule in", self.autoturn_sec) UIManager:scheduleIn(self.autoturn_sec, self.task) @@ -60,10 +59,10 @@ end function AutoTurn:_start() if self:_enabled() then - local now = UIManager:getTime() - logger.dbg("AutoTurn: start at", time.format_time(now)) + local time_since_boot = UIManager:getElapsedTimeSinceBoot() + logger.dbg("AutoTurn: start at", time.format_time(time_since_boot)) PluginShare.pause_auto_suspend = true - self.last_action_time = now + self.last_action_time = time_since_boot self:_schedule() local text @@ -109,11 +108,7 @@ end function AutoTurn:onInputEvent() logger.dbg("AutoTurn: onInputEvent") - self.last_action_time = UIManager:getTime() -end - -function AutoTurn:onEnterStandby() - self:_unschedule() + self.last_action_time = UIManager:getElapsedTimeSinceBoot() end -- We do not want autoturn to turn pages during the suspend process. @@ -123,16 +118,6 @@ function AutoTurn:onSuspend() self:_unschedule() end -function AutoTurn:_onLeaveStandby() - self.last_action_time = self.last_action_time - Device.last_standby_time - - -- We messed with last_action_time, so a complete reschedule has to be done. - if self:_enabled() then - self:_unschedule() - self:_schedule() - end -end - function AutoTurn:_onResume() logger.dbg("AutoTurn: onResume") self:_start() @@ -168,7 +153,6 @@ function AutoTurn:addToMainMenu(menu_items) self:_unschedule() menu:updateItems() self.onResume = nil - self.onLeaveStandby = nil end, ok_always_enabled = true, callback = function(t) @@ -180,7 +164,6 @@ function AutoTurn:addToMainMenu(menu_items) self:_start() menu:updateItems() self.onResume = self._onResume - self.onLeaveStandby = self._onLeaveStandby end, } UIManager:show(autoturn_spin) diff --git a/plugins/autowarmth.koplugin/main.lua b/plugins/autowarmth.koplugin/main.lua index 7496fe1ab..5f8f9f3d5 100644 --- a/plugins/autowarmth.koplugin/main.lua +++ b/plugins/autowarmth.koplugin/main.lua @@ -137,7 +137,9 @@ function AutoWarmth:onAutoWarmthMode() self:scheduleMidnightUpdate() end -function AutoWarmth:leavePowerSavingState(from_resume) +function AutoWarmth:_onResume() + logger.dbg("AutoWarmth: onResume") + local resume_date = os.date("*t") -- check if resume and suspend are done on the same day @@ -146,26 +148,16 @@ function AutoWarmth:leavePowerSavingState(from_resume) local now_s = SunTime:getTimeInSec(resume_date) self.sched_warmth_index = self.sched_warmth_index - 1 -- scheduleNextWarmth will check this - self:scheduleNextWarmthChange(from_resume) + self:scheduleNextWarmthChange(true) self:scheduleToggleFrontlight(now_s) -- reset user toggles at sun set or sun rise self:toggleFrontlight(now_s) -- Reschedule 1sec after midnight UIManager:scheduleIn(24*3600 + 1 - now_s, self.scheduleMidnightUpdate, self) else - self:scheduleMidnightUpdate(from_resume) -- resume is on the other day, do all calcs again + self:scheduleMidnightUpdate(true) -- resume is on the other day, do all calcs again end end -function AutoWarmth:_onResume() - logger.dbg("AutoWarmth: onResume") - self:leavePowerSavingState(true) -end - -function AutoWarmth:_onLeaveStandby() - logger.dbg("AutoWarmth: onLeaveStandby") - self:leavePowerSavingState(false) -end - function AutoWarmth:_onSuspend() logger.dbg("AutoWarmth: onSuspend") UIManager:unschedule(self.scheduleMidnightUpdate) @@ -173,8 +165,6 @@ function AutoWarmth:_onSuspend() UIManager:unschedule(self.setFrontlight) end -AutoWarmth._onEnterStandby = AutoWarmth._onSuspend - function AutoWarmth:_onToggleNightMode() logger.dbg("AutoWarmth: onToggleNightMode") if not self.hide_nightmode_warning then @@ -220,8 +210,6 @@ end function AutoWarmth:setEventHandlers() self.onResume = self._onResume self.onSuspend = self._onSuspend - self.onEnterStandby = self._onEnterStandby - self.onLeaveStandby = self._onLeaveStandby if self.control_nightmode then self.onToggleNightMode = self._onToggleNightMode self.onSetNightMode = self._onToggleNightMode @@ -234,8 +222,6 @@ end function AutoWarmth:clearEventHandlers() self.onResume = nil self.onSuspend = nil - self.onEnterStandby = nil - self.onLeaveStandby = nil self.onToggleNightMode = nil self.onSetNightMode = nil self.onToggleFrontlight = nil