AutoSuspend: Make sure we send a LeaveStandby event ASAP (#9173)

Even in corner cases where we're woken up without user input (e.g., rtc alarm).

(Followup to #9124)
reviewable/pr9182/r1
NiLuJe 2 years ago committed by GitHub
parent c825d50c8f
commit 73b2b38954
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -145,12 +145,10 @@ function ReaderCoptListener:onResume()
end
self:headerRefresh()
self:rescheduleHeaderRefreshIfNeeded()
end
function ReaderCoptListener:onLeaveStandby()
self:headerRefresh()
self:rescheduleHeaderRefreshIfNeeded()
end
function ReaderCoptListener:onOutOfScreenSaver()
@ -160,7 +158,6 @@ function ReaderCoptListener:onOutOfScreenSaver()
self._delayed_screensaver = nil
self:headerRefresh()
self:rescheduleHeaderRefreshIfNeeded()
end
-- Unschedule on these events

@ -766,8 +766,9 @@ end
function ReaderFooter:unscheduleFooterAutoRefresh()
if not self.autoRefreshFooter then return end -- not yet set up
-- Slightly different wording than in rescheduleFooterAutoRefreshIfNeeded because it might not actually be scheduled at all
logger.dbg("ReaderFooter: unschedule autoRefreshFooter")
UIManager:unschedule(self.autoRefreshFooter)
logger.dbg("ReaderFooter.autoRefreshFooter unscheduled")
end
function ReaderFooter:rescheduleFooterAutoRefreshIfNeeded()
@ -808,12 +809,12 @@ function ReaderFooter:rescheduleFooterAutoRefreshIfNeeded()
if schedule then
UIManager:scheduleIn(61 - tonumber(os.date("%S")), self.autoRefreshFooter)
if not unscheduled then
logger.dbg("ReaderFooter.autoRefreshFooter scheduled")
logger.dbg("ReaderFooter: scheduled autoRefreshFooter")
else
logger.dbg("ReaderFooter.autoRefreshFooter rescheduled")
logger.dbg("ReaderFooter: rescheduled autoRefreshFooter")
end
elseif unscheduled then
logger.dbg("ReaderFooter.autoRefreshFooter unscheduled")
logger.dbg("ReaderFooter: unscheduled autoRefreshFooter")
end
end

@ -1659,6 +1659,12 @@ function UIManager:handleInput()
-- this function emits (plugin), or within waitEvent() right after (hardware).
-- Anywhere else breaks preventStandby/allowStandby invariants used by background jobs while UI is left running.
self:_standbyTransition()
if self.PM_INPUT_TIMEOUT then
-- If the PM state transition requires an early return from input polling, honor that.
-- c.f., UIManager:setPMInputTimeout (and AutoSuspend:AllowStandbyHandler).
deadline = now + time.s(self.PM_INPUT_TIMEOUT)
self.PM_INPUT_TIMEOUT = nil
end
-- wait for next batch of events
local input_events = Input:waitEvent(now, deadline)
@ -1841,6 +1847,12 @@ function UIManager:_standbyTransition()
self._prev_prevent_standby_count = self._prevent_standby_count
end
-- Used by a PM transition event handler to request an early return from input polling (value in s).
-- NOTE: We can't re-use setInputTimeout to avoid interactions with ZMQ...
function UIManager:setPMInputTimeout(timeout)
self.PM_INPUT_TIMEOUT = timeout
end
--- Broadcasts a `FlushSettings` Event to *all* widgets.
function UIManager:flushSettings()
self:broadcastEvent(Event:new("FlushSettings"))

@ -204,12 +204,6 @@ function AutoSuspend:_unschedule_standby()
end
-- Make sure we don't trigger a ghost LeaveStandby event...
if self.wrapped_leave_standby_task then
logger.dbg("AutoSuspend: unschedule leave standby task wrapper")
UIManager:unschedule(self.wrapped_leave_standby_task)
self.wrapped_leave_standby_task = nil
end
if self.leave_standby_task then
logger.dbg("AutoSuspend: unschedule leave standby task")
UIManager:unschedule(self.leave_standby_task)
@ -338,8 +332,6 @@ end
function AutoSuspend:onLeaveStandby()
logger.dbg("AutoSuspend: onLeaveStandby")
-- If the Event got through, tickAfterNext did its thing, clear the reference to the initial nextTick wrapper...
self.wrapped_leave_standby_task = nil
-- 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).
@ -599,8 +591,21 @@ function AutoSuspend:AllowStandbyHandler()
-- 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: UIManager consumes scheduled tasks before input events, which is why we can't use nextTick.
self.wrapped_leave_standby_task = UIManager:tickAfterNext(self.leave_standby_task)
-- NOTE: While UIManager consumes scheduled tasks before input events, we do *NOT* have to rely on tickAfterNext,
-- 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)
-- 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:setPMInputTimeout(0)
end
end

Loading…
Cancel
Save