From c7f5bfb72a4f0114182f75db992451f37de617c6 Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Mon, 7 Nov 2022 17:40:45 +0100 Subject: [PATCH] ScreenSaver: Handle Power button presses properly if the screensaver lock is enabled Fix #9744 --- frontend/device/cervantes/device.lua | 34 +++++++----------------- frontend/device/generic/device.lua | 4 +-- frontend/device/kindle/device.lua | 6 ++--- frontend/device/kobo/device.lua | 13 ++++++++- frontend/device/remarkable/device.lua | 9 ++++++- frontend/device/sdl/device.lua | 7 ++--- frontend/device/sony-prstux/device.lua | 6 ++--- frontend/ui/screensaver.lua | 5 ++++ frontend/ui/widget/screensaverwidget.lua | 16 +++++++++++ spec/unit/device_spec.lua | 6 ++--- 10 files changed, 60 insertions(+), 46 deletions(-) diff --git a/frontend/device/cervantes/device.lua b/frontend/device/cervantes/device.lua index 81bc26f19..4ed1aa287 100644 --- a/frontend/device/cervantes/device.lua +++ b/frontend/device/cervantes/device.lua @@ -49,6 +49,7 @@ local Cervantes = Generic:extend{ canReboot = yes, canPowerOff = yes, canSuspend = yes, + supportsScreensaver = yes, home_dir = "/mnt/public", -- do we support usb mass storage? @@ -198,30 +199,6 @@ function Cervantes:initNetworkManager(NetworkMgr) end end --- screensaver -function Cervantes:supportsScreensaver() - return true -end -function Cervantes:intoScreenSaver() - local Screensaver = require("ui/screensaver") - if self.screen_saver_mode == false then - Screensaver:setup() - Screensaver:show() - end - self.powerd:beforeSuspend() - self.screen_saver_mode = true -end -function Cervantes:outofScreenSaver() - if self.screen_saver_mode == true then - local Screensaver = require("ui/screensaver") - Screensaver:close() - local UIManager = require("ui/uimanager") - UIManager:nextTick(function() UIManager:setDirty("all", "full") end) - end - self.powerd:afterResume() - self.screen_saver_mode = false -end - -- power functions: suspend, resume, reboot, poweroff function Cervantes:suspend() os.execute("./suspend.sh") @@ -263,7 +240,14 @@ function Cervantes:setEventHandlers(UIManager) UIManager:unschedule(UIManager.poweroff_action) -- resume if we were suspended if self.screen_saver_mode then - UIManager.event_handlers.Resume() + if self.screen_saver_lock then + logger.dbg("Pressed power while awake in screen saver mode, going back to suspend...") + self:_beforeSuspend() + self.powerd:beforeSuspend() -- this won't be run by onPowerEvent because we're in screen_saver_mode + self:onPowerEvent("Suspend") + else + UIManager.event_handlers.Resume() + end else UIManager.event_handlers.Suspend() end diff --git a/frontend/device/generic/device.lua b/frontend/device/generic/device.lua index d4151426c..b10916869 100644 --- a/frontend/device/generic/device.lua +++ b/frontend/device/generic/device.lua @@ -257,7 +257,7 @@ function Device:onPowerEvent(ev) if self.screen_saver_mode then if ev == "Power" or ev == "Resume" then if self.is_cover_closed then - -- don't let power key press wake up device when the cover is in closed state + -- don't let power key press wake up device when the cover is in closed state. self:rescheduleSuspend() else logger.dbg("Resuming...") @@ -275,7 +275,6 @@ function Device:onPowerEvent(ev) if widget_was_closed and self:needsScreenRefreshAfterResume() then UIManager:scheduleIn(1, function() self.screen:refreshFull() end) end - self.screen_saver_mode = false self.powerd:afterResume() end elseif ev == "Suspend" then @@ -304,7 +303,6 @@ function Device:onPowerEvent(ev) if self:needsScreenRefreshAfterResume() then self.screen:refreshFull() end - self.screen_saver_mode = true UIManager:scheduleIn(0.1, function() -- NOTE: This side of the check needs to be laxer, some platforms can handle Wi-Fi without WifiManager ;). if self:hasWifiToggle() then diff --git a/frontend/device/kindle/device.lua b/frontend/device/kindle/device.lua index 417da4c21..1005f5998 100644 --- a/frontend/device/kindle/device.lua +++ b/frontend/device/kindle/device.lua @@ -280,7 +280,7 @@ function Kindle:usbPlugIn() end function Kindle:intoScreenSaver() - if self.screen_saver_mode == false then + if not self.screen_saver_mode then if self:supportsScreensaver() then -- NOTE: Meaning this is not a SO device ;) local Screensaver = require("ui/screensaver") @@ -296,11 +296,10 @@ function Kindle:intoScreenSaver() end end self.powerd:beforeSuspend() - self.screen_saver_mode = true end function Kindle:outofScreenSaver() - if self.screen_saver_mode == true then + if self.screen_saver_mode then if self:supportsScreensaver() then local Screensaver = require("ui/screensaver") local widget_was_closed = Screensaver:close() @@ -349,7 +348,6 @@ function Kindle:outofScreenSaver() end end self.powerd:afterResume() - self.screen_saver_mode = false end function Kindle:usbPlugOut() diff --git a/frontend/device/kobo/device.lua b/frontend/device/kobo/device.lua index 9c733c085..4de15b6af 100644 --- a/frontend/device/kobo/device.lua +++ b/frontend/device/kobo/device.lua @@ -1382,7 +1382,18 @@ function Kobo:setEventHandlers(uimgr) UIManager:unschedule(UIManager.poweroff_action) -- resume if we were suspended if self.screen_saver_mode then - UIManager.event_handlers.Resume() + if self.screen_saver_lock then + -- This can only happen when some sort of screensaver_delay is set, + -- and the user presses the Power button *after* already having woken up the device. + -- In this case, we want to go back to suspend *without* affecting the screensaver, + -- so we mimic UIManager.event_handlers.Suspend's behavior when *not* in screen_saver_mode ;). + logger.dbg("Pressed power while awake in screen saver mode, going back to suspend...") + self:_beforeSuspend() + self.powerd:beforeSuspend() -- this won't be run by onPowerEvent because we're in screen_saver_mode + self:onPowerEvent("Suspend") + else + UIManager.event_handlers.Resume() + end else UIManager.event_handlers.Suspend() end diff --git a/frontend/device/remarkable/device.lua b/frontend/device/remarkable/device.lua index dc00b8557..36d6033b7 100644 --- a/frontend/device/remarkable/device.lua +++ b/frontend/device/remarkable/device.lua @@ -249,7 +249,14 @@ function Remarkable:setEventHandlers(UIManager) UIManager:unschedule(UIManager.poweroff_action) -- resume if we were suspended if self.screen_saver_mode then - UIManager.event_handlers.Resume() + if self.screen_saver_lock then + logger.dbg("Pressed power while awake in screen saver mode, going back to suspend...") + self:_beforeSuspend() + self.powerd:beforeSuspend() -- this won't be run by onPowerEvent because we're in screen_saver_mode + self:onPowerEvent("Suspend") + else + UIManager.event_handlers.Resume() + end else UIManager.event_handlers.Suspend() end diff --git a/frontend/device/sdl/device.lua b/frontend/device/sdl/device.lua index 73677523c..1c0fe7223 100644 --- a/frontend/device/sdl/device.lua +++ b/frontend/device/sdl/device.lua @@ -345,9 +345,8 @@ end function Device:setEventHandlers(UIManager) if not self:canSuspend() then - -- If we can't suspend, we have no business even trying to, as we may not have overloaded `Device:simulateResume`, - -- and since the empty Generic prototype doesn't flip `Device.screen_saver_mode`, we'd be stuck if we tried... - -- Instead, rely on the Generic Suspend/Resume handlers, which are sane ;). + -- If we can't suspend, we have no business even trying to, as we may not have overloaded `Device:simulateResume`. + -- Instead, rely on the Generic Suspend/Resume handlers. return end @@ -375,13 +374,11 @@ function Emulator:simulateSuspend() local Screensaver = require("ui/screensaver") Screensaver:setup() Screensaver:show() - self.screen_saver_mode = true end function Emulator:simulateResume() local Screensaver = require("ui/screensaver") Screensaver:close() - self.screen_saver_mode = false end -- fake network manager for the emulator diff --git a/frontend/device/sony-prstux/device.lua b/frontend/device/sony-prstux/device.lua index e6534db0f..3ac97896f 100644 --- a/frontend/device/sony-prstux/device.lua +++ b/frontend/device/sony-prstux/device.lua @@ -91,23 +91,21 @@ end function SonyPRSTUX:intoScreenSaver() local Screensaver = require("ui/screensaver") - if self.screen_saver_mode == false then + if not self.screen_saver_mode then Screensaver:setup() Screensaver:show() end self.powerd:beforeSuspend() - self.screen_saver_mode = true end function SonyPRSTUX:outofScreenSaver() - if self.screen_saver_mode == true then + if self.screen_saver_mode then local Screensaver = require("ui/screensaver") Screensaver:close() local UIManager = require("ui/uimanager") UIManager:nextTick(function() UIManager:setDirty("all", "full") end) end self.powerd:afterResume() - self.screen_saver_mode = false end function SonyPRSTUX:suspend() diff --git a/frontend/ui/screensaver.lua b/frontend/ui/screensaver.lua index b4f444b40..8db0e7978 100644 --- a/frontend/ui/screensaver.lua +++ b/frontend/ui/screensaver.lua @@ -582,10 +582,13 @@ function Screensaver:setup(event, event_message) end function Screensaver:show() + -- This should never happen... if self.screensaver_widget then UIManager:close(self.screensaver_widget) self.screensaver_widget = nil end + -- Notify Device methods that we're in screen saver mode, so they know whether to suspend or resume on Power events. + Device.screen_saver_mode = true -- In as-is mode with no message and no overlay, we've got nothing to show :) if self.screensaver_type == "disable" and not self.show_message and not self.overlay_message then @@ -804,6 +807,8 @@ end function Screensaver:close() if self.screensaver_widget == nil then + -- When we *do* have a widget, this is handled by ScreenSaverWidget:onCloseWidget ;). + Device.screen_saver_mode = false return end diff --git a/frontend/ui/widget/screensaverwidget.lua b/frontend/ui/widget/screensaverwidget.lua index 72f19eaa3..49586756c 100644 --- a/frontend/ui/widget/screensaverwidget.lua +++ b/frontend/ui/widget/screensaverwidget.lua @@ -163,6 +163,9 @@ ScreenSaverWidget.onAnyKeyPressed = ScreenSaverWidget.onClose ScreenSaverWidget.onExitScreensaver = ScreenSaverWidget.onClose function ScreenSaverWidget:onCloseWidget() + Device.screen_saver_mode = false + Device.screen_saver_lock = false + -- Restore to previous rotation mode, if need be. if Device.orig_rotation_mode then Screen:setRotationMode(Device.orig_rotation_mode) @@ -179,4 +182,17 @@ function ScreenSaverWidget:onCloseWidget() UIManager:broadcastEvent(Event:new("OutOfScreenSaver")) end +function ScreenSaverWidget:onResume() + -- If we actually catch this event, it means screensaver_delay is set. + -- Tell Device about it, so that further power button presses while we're still shown send us back to suspend. + -- NOTE: This only affects devices where we handle Power events ourselves (i.e., rely on Device -> Generic's onPowerEvent), + -- and it *always* implies that Device.screen_saver_mode is true. + Device.screen_saver_lock = true +end + +function ScreenSaverWidget:onSuspend() + -- Also flip this back on suspend, in case we suspend again on a delayed screensaver (e.g., via SleepCover or AutoSuspend). + Device.screen_saver_lock = false +end + return ScreenSaverWidget diff --git a/spec/unit/device_spec.lua b/spec/unit/device_spec.lua index 8247e4ae7..4d15c9a1c 100644 --- a/spec/unit/device_spec.lua +++ b/spec/unit/device_spec.lua @@ -350,8 +350,8 @@ describe("device module", function() Device.suspend:revert() Device.powerd.beforeSuspend:revert() Device.isCervantes:revert() - Device.screen_saver_mode = false readerui.onFlushSettings:revert() + Device.screen_saver_mode = false readerui:onClose() end) @@ -381,8 +381,8 @@ describe("device module", function() Device.suspend:revert() Device.powerd.beforeSuspend:revert() Device.isSDL:revert() - Device.screen_saver_mode = false readerui.onFlushSettings:revert() + Device.screen_saver_mode = false readerui:onClose() end) @@ -431,8 +431,8 @@ describe("device module", function() Device.suspend:revert() Device.powerd.beforeSuspend:revert() Device.isRemarkable:revert() - Device.screen_saver_mode = false readerui.onFlushSettings:revert() + Device.screen_saver_mode = false readerui:onClose() end) end)