From 4005bf69aa5667f520a1e837f9c493874cf192fa Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Mon, 8 Apr 2019 23:05:08 +0200 Subject: [PATCH] Slightly less crappy Nightmode (#4871) Companion PR to https://github.com/koreader/koreader-base/pull/884 * Basically flags devices known to be stable when using PxP inversion. * Plus, random fix for #4870 ;). * A few FrontLight tweaks & cleanups on Kobo: * Moved the Kobo-specific startup status insanity to Kobo-specific init * Made turnOff/turnOn frontlight do a smooth ramp down/up * On Kobo, use turnOff/turnOn for suspend/resume, to get that smooth toggle * On Kobo, for NaturalLight w/ a mixer, only set warmth for setWarmth, and only set Brightness for setBrightness, otherwise, it tried to set both with not in-sync values, which made the FL widget jittery. --- base | 2 +- frontend/apps/filemanager/filemanagermenu.lua | 2 +- .../apps/reader/modules/readerfrontlight.lua | 4 +- .../apps/reader/modules/readergesture.lua | 2 +- frontend/device/cervantes/powerd.lua | 10 +- frontend/device/generic/device.lua | 1 + frontend/device/generic/powerd.lua | 33 ++--- frontend/device/kindle/device.lua | 6 + frontend/device/kindle/powerd.lua | 4 +- frontend/device/kobo/device.lua | 4 + frontend/device/kobo/powerd.lua | 68 +++++++--- frontend/device/pocketbook/powerd.lua | 2 +- frontend/device/sony-prstux/powerd.lua | 2 +- frontend/device/sysfs_light.lua | 22 ++-- .../elements/common_settings_menu_table.lua | 7 +- frontend/ui/widget/inputtext.lua | 6 +- reader.lua | 6 +- spec/unit/autofrontlight_spec.lua | 3 + spec/unit/frontlight_spec.lua | 119 ++++++++++-------- 19 files changed, 181 insertions(+), 122 deletions(-) diff --git a/base b/base index ed048193e..19e38d0be 160000 --- a/base +++ b/base @@ -1 +1 @@ -Subproject commit ed048193eca6ebf85d3364edd0cd7a5bb5c1c4f1 +Subproject commit 19e38d0be9191dfdbf4ba0d225e635b98f3ec4fd diff --git a/frontend/apps/filemanager/filemanagermenu.lua b/frontend/apps/filemanager/filemanagermenu.lua index cc527bfae..51ab85b13 100644 --- a/frontend/apps/filemanager/filemanagermenu.lua +++ b/frontend/apps/filemanager/filemanagermenu.lua @@ -257,7 +257,7 @@ function FileManagerMenu:setUpdateItemTable() } if Device:isKobo() then table.insert(self.menu_items.developer_options.sub_item_table, { - text = _("Disable forced 8-bit color space"), + text = _("Disable forced 8-bit pixel depth"), checked_func = function() return G_reader_settings:isTrue("dev_startup_no_fbdepth") end, diff --git a/frontend/apps/reader/modules/readerfrontlight.lua b/frontend/apps/reader/modules/readerfrontlight.lua index d04a50761..18ba3d6f8 100644 --- a/frontend/apps/reader/modules/readerfrontlight.lua +++ b/frontend/apps/reader/modules/readerfrontlight.lua @@ -38,7 +38,7 @@ function ReaderFrontLight:init() end function ReaderFrontLight:onAdjust(arg, ges) - if not Device.hasFrontlight() then return true end + if not Device:hasFrontlight() then return true end local powerd = Device:getPowerDevice() logger.dbg("frontlight intensity", powerd:frontlightIntensity()) local step = math.ceil(#self.steps * ges.distance / self.gestureScale) @@ -65,7 +65,7 @@ function ReaderFrontLight:onAdjust(arg, ges) end function ReaderFrontLight:onShowIntensity() - if not Device.hasFrontlight() then return true end + if not Device:hasFrontlight() then return true end local powerd = Device:getPowerDevice() local new_text if powerd:isFrontlightOff() then diff --git a/frontend/apps/reader/modules/readergesture.lua b/frontend/apps/reader/modules/readergesture.lua index 6685226c8..356afc4dd 100644 --- a/frontend/apps/reader/modules/readergesture.lua +++ b/frontend/apps/reader/modules/readergesture.lua @@ -844,7 +844,7 @@ function ReaderGesture:gestureAction(action, ges) elseif action == "toc" then self.ui:handleEvent(Event:new("ShowToc")) elseif action == "night_mode" then - local night_mode = G_reader_settings:readSetting("night_mode") or false + local night_mode = G_reader_settings:isTrue("night_mode") Screen:toggleNightMode() UIManager:setDirty("all", "full") G_reader_settings:saveSetting("night_mode", not night_mode) diff --git a/frontend/device/cervantes/powerd.lua b/frontend/device/cervantes/powerd.lua index d2fc72b06..4a67adf3e 100644 --- a/frontend/device/cervantes/powerd.lua +++ b/frontend/device/cervantes/powerd.lua @@ -63,8 +63,8 @@ function CervantesPowerD:init() self.initial_is_fl_on = true self.autowarmth_job_running = false - if self.device.hasFrontlight() then - if self.device.hasNaturalLight() then + if self.device:hasFrontlight() then + if self.device:hasNaturalLight() then local nl_config = G_reader_settings:readSetting("natural_light_config") if nl_config then for key,val in pairs(nl_config) do @@ -86,7 +86,7 @@ function CervantesPowerD:init() end function CervantesPowerD:saveSettings() - if self.device.hasFrontlight() then + if self.device:hasFrontlight() then -- Store BasePowerD values into settings (and not our hw_intensity, so -- that if frontlight was toggled off, we save and restore the previous -- untoggled intensity and toggle state at next startup) @@ -121,10 +121,6 @@ function CervantesPowerD:isFrontlightOnHW() return self.hw_intensity > 0 end -function CervantesPowerD:turnOffFrontlightHW() - self:_setIntensity(0) -- will call setIntensityHW(0) -end - function CervantesPowerD:setIntensityHW(intensity) if self.fl == nil then return end if self.fl_warmth == nil then diff --git a/frontend/device/generic/device.lua b/frontend/device/generic/device.lua index 654d240c0..1de7dd9b8 100644 --- a/frontend/device/generic/device.lua +++ b/frontend/device/generic/device.lua @@ -31,6 +31,7 @@ local Device = { hasClipboard = yes, -- generic internal clipboard on all devices hasEinkScreen = yes, canHWDither = no, + canHWInvert = no, hasColorScreen = no, hasBGRFrameBuffer = no, canToggleGSensor = no, diff --git a/frontend/device/generic/powerd.lua b/frontend/device/generic/powerd.lua index 04c0dcad7..294f42b64 100644 --- a/frontend/device/generic/powerd.lua +++ b/frontend/device/generic/powerd.lua @@ -17,24 +17,9 @@ function BasePowerD:new(o) self.__index = self assert(o.fl_min < o.fl_max) if o.init then o:init() end - if o.device and o.device.hasFrontlight() then + if o.device and o.device:hasFrontlight() then o.fl_intensity = o:frontlightIntensityHW() o:_decideFrontlightState() - -- Note added by @Frenzie 2017-10-08 - -- I believe this should be `if isKobo()`, or better yet that the entire - -- block should be moved to `KoboPowerD:init()` because afaik that is the - -- only platform where the system doesn't provide trustworthy frontlight - -- information. But to be absolutely sure that I don't break anything (and I - -- don't want to spend any time on this atm) I'm temporarily excluding only - -- Android where this behavior is known to be problematic. - -- See discussion in https://github.com/koreader/koreader/issues/3118#issuecomment-334995879 - if not o.device:isAndroid() then - if o:isFrontlightOn() then - o:turnOnFrontlightHW() - else - o:turnOffFrontlightHW() - end - end end return o end @@ -63,7 +48,7 @@ end function BasePowerD:_decideFrontlightState() assert(self ~= nil) - assert(self.device.hasFrontlight()) + assert(self.device:hasFrontlight()) self.is_fl_on = self:isFrontlightOnHW() end @@ -73,14 +58,14 @@ end function BasePowerD:frontlightIntensity() assert(self ~= nil) - if not self.device.hasFrontlight() then return 0 end + if not self.device:hasFrontlight() then return 0 end if self:isFrontlightOff() then return 0 end return self.fl_intensity end function BasePowerD:toggleFrontlight() assert(self ~= nil) - if not self.device.hasFrontlight() then return false end + if not self.device:hasFrontlight() then return false end if self:isFrontlightOn() then return self:turnOffFrontlight() else @@ -90,20 +75,20 @@ end function BasePowerD:turnOffFrontlight() assert(self ~= nil) - if not self.device.hasFrontlight() then return end + if not self.device:hasFrontlight() then return end if self:isFrontlightOff() then return false end - self.is_fl_on = false self:turnOffFrontlightHW() + self.is_fl_on = false return true end function BasePowerD:turnOnFrontlight() assert(self ~= nil) - if not self.device.hasFrontlight() then return end + if not self.device:hasFrontlight() then return end if self:isFrontlightOn() then return false end if self.fl_intensity == self.fl_min then return false end - self.is_fl_on = true self:turnOnFrontlightHW() + self.is_fl_on = true return true end @@ -135,7 +120,7 @@ function BasePowerD:normalizeIntensity(intensity) end function BasePowerD:setIntensity(intensity) - if not self.device.hasFrontlight() then return false end + if not self.device:hasFrontlight() then return false end if intensity == self:frontlightIntensity() then return false end self.fl_intensity = self:normalizeIntensity(intensity) self:_decideFrontlightState() diff --git a/frontend/device/kindle/device.lua b/frontend/device/kindle/device.lua index bf9ba5bb3..0eb446de5 100644 --- a/frontend/device/kindle/device.lua +++ b/frontend/device/kindle/device.lua @@ -75,6 +75,8 @@ local Kindle = Generic:new{ -- NOTE: We can cheat by adding a platform-specific entry here, because the only code that will check for this is here. isSpecialOffers = isSpecialOffers(), hasOTAUpdates = yes, + -- NOTE: HW inversion is generally safe on mxcfb Kindles + canHWInvert = yes, } function Kindle:initNetworkManager(NetworkMgr) @@ -206,6 +208,7 @@ local Kindle2 = Kindle:new{ hasKeyboard = yes, hasKeys = yes, hasDPad = yes, + canHWInvert = no, } local KindleDXG = Kindle:new{ @@ -213,6 +216,7 @@ local KindleDXG = Kindle:new{ hasKeyboard = yes, hasKeys = yes, hasDPad = yes, + canHWInvert = no, } local Kindle3 = Kindle:new{ @@ -220,12 +224,14 @@ local Kindle3 = Kindle:new{ hasKeyboard = yes, hasKeys = yes, hasDPad = yes, + canHWInvert = no, } local Kindle4 = Kindle:new{ model = "Kindle4", hasKeys = yes, hasDPad = yes, + canHWInvert = no, } local KindleTouch = Kindle:new{ diff --git a/frontend/device/kindle/powerd.lua b/frontend/device/kindle/powerd.lua index 140079dbb..e723d5ec1 100644 --- a/frontend/device/kindle/powerd.lua +++ b/frontend/device/kindle/powerd.lua @@ -15,7 +15,7 @@ function KindlePowerD:init() end function KindlePowerD:frontlightIntensityHW() - if not self.device.hasFrontlight() then return 0 end + if not self.device:hasFrontlight() then return 0 end -- Kindle stock software does not use intensity file directly, so we need to read from its -- lipc property first. if self.lipc_handle ~= nil then @@ -73,7 +73,7 @@ function KindlePowerD:_readFLIntensity() end function KindlePowerD:afterResume() - if not self.device.hasFrontlight() then + if not self.device:hasFrontlight() then return end local UIManager = require("ui/uimanager") diff --git a/frontend/device/kobo/device.lua b/frontend/device/kobo/device.lua index 647e1e7c8..f8bc2efb2 100644 --- a/frontend/device/kobo/device.lua +++ b/frontend/device/kobo/device.lua @@ -38,6 +38,8 @@ local Kobo = Generic:new{ internal_storage_mount_point = "/mnt/onboard/", -- currently only the Aura One and Forma have coloured frontlights hasNaturalLight = no, + -- HW inversion is generally safe on Kobo, except on a few baords/kernels + canHWInvert = yes, } -- TODO: hasKeys for some devices? @@ -114,6 +116,8 @@ local KoboPhoenix = Kobo:new{ display_dpi = 212, -- the bezel covers 12 pixels at the bottom: viewport = Geom:new{x=0, y=0, w=758, h=1012}, + -- NOTE: May have a buggy kernel, according to the nightmode hack... + canHWInvert = no, } -- Kobo Aura H2O2: diff --git a/frontend/device/kobo/powerd.lua b/frontend/device/kobo/powerd.lua index 205b0f176..eec8ca3fd 100644 --- a/frontend/device/kobo/powerd.lua +++ b/frontend/device/kobo/powerd.lua @@ -112,12 +112,12 @@ function KoboPowerD:init() self.initial_is_fl_on = true self.autowarmth_job_running = false - if self.device.hasFrontlight() then + if self.device:hasFrontlight() then -- If this device has natural light (currently only KA1 & Forma) -- Use the SysFS interface, and ioctl otherwise. -- NOTE: On the Forma, nickel still appears to prefer using ntx_io to handle the FL, -- but it does use sysfs for the NL... - if self.device.hasNaturalLight() then + if self.device:hasNaturalLight() then local nl_config = G_reader_settings:readSetting("natural_light_config") if nl_config then for key,val in pairs(nl_config) do @@ -138,11 +138,20 @@ function KoboPowerD:init() self:_syncKoboLightOnStart() end end + -- See discussion in https://github.com/koreader/koreader/issues/3118#issuecomment-334995879 + -- for the reasoning behind this bit of insanity. + if self:isFrontlightOnHW() then + -- Use setIntensity to ensure it sets fl_intensity, and because we don't want the ramping behavior of turnOn + self:setIntensity(self:frontlightIntensityHW()) + else + -- Use setIntensityHW so as *NOT* to set fl_intensity, so toggle will still work. + self:setIntensityHW(0) + end end end function KoboPowerD:saveSettings() - if self.device.hasFrontlight() then + if self.device:hasFrontlight() then -- Store BasePowerD values into settings (and not our hw_intensity, so -- that if frontlight was toggled off, we save and restore the previous -- untoggled intensity and toggle state at next startup) @@ -201,10 +210,6 @@ function KoboPowerD:isFrontlightOnHW() return self.hw_intensity > 0 end -function KoboPowerD:turnOffFrontlightHW() - self:_setIntensity(0) -- will call setIntensityHW(0) -end - function KoboPowerD:setIntensityHW(intensity) if self.fl == nil then return end if self.fl_warmth == nil then @@ -271,25 +276,52 @@ function KoboPowerD:isChargingHW() return self:read_str_file(self.is_charging_file) == "Charging\n" end +function KoboPowerD:turnOffFrontlightHW() + if self:isFrontlightOff() then + return + end + local util = require("ffi/util") + util.runInSubProcess(function() + for i = 1,5 do + self:_setIntensity(math.floor(self.fl_intensity - ((self.fl_intensity / 5) * i))) + -- NOTE: We generally don't need to sleep when using sysfs as a backend... + if not self.device:hasNaturalLight() then + if (i < 5) then + util.usleep(35 * 1000) + end + end + end + end, false, true) +end +function KoboPowerD:turnOnFrontlightHW() + if self:isFrontlightOn() then + return + end + local util = require("ffi/util") + util.runInSubProcess(function() + for i = 1,5 do + self:_setIntensity(math.ceil(self.fl_min + ((self.fl_intensity / 5) * i))) + if not self.device:hasNaturalLight() then + if (i < 5) then + util.usleep(35 * 1000) + end + end + end + end, false, true) +end + -- Turn off front light before suspend. function KoboPowerD:beforeSuspend() if self.fl == nil then return end - -- just turn off frontlight without remembering its state - self.fl:setBrightness(0) + -- Turn off the frontlight + self:turnOffFrontlight() end -- Restore front light state after resume. function KoboPowerD:afterResume() if self.fl == nil then return end - -- just re-set it to self.hw_intensity that we haven't change on Suspend - if self.fl_warmth == nil then - self.fl:setBrightness(self.hw_intensity) - else - if self.auto_warmth then - self:calculateAutoWarmth() - end - self.fl:setNaturalBrightness(self.hw_intensity, self.fl_warmth) - end + -- Turn the frontlight back on + self:turnOnFrontlight() end return KoboPowerD diff --git a/frontend/device/pocketbook/powerd.lua b/frontend/device/pocketbook/powerd.lua index b9bcf633d..cc3aa3c0f 100644 --- a/frontend/device/pocketbook/powerd.lua +++ b/frontend/device/pocketbook/powerd.lua @@ -22,7 +22,7 @@ function PocketBookPowerD:init() end function PocketBookPowerD:frontlightIntensityHW() - if not self.device.hasFrontlight() then return 0 end + if not self.device:hasFrontlight() then return 0 end return inkview.GetFrontlightState() end diff --git a/frontend/device/sony-prstux/powerd.lua b/frontend/device/sony-prstux/powerd.lua index ba324e7f4..3f1264e5e 100644 --- a/frontend/device/sony-prstux/powerd.lua +++ b/frontend/device/sony-prstux/powerd.lua @@ -14,7 +14,7 @@ function SonyPRSTUX_PowerD:init() end function SonyPRSTUX_PowerD:frontlightIntensityHW() - if not self.device.hasFrontlight() then return 0 end + if not self.device:hasFrontlight() then return 0 end end function SonyPRSTUX_PowerD:setIntensityHW(intensity) diff --git a/frontend/device/sysfs_light.lua b/frontend/device/sysfs_light.lua index f5c5d8d9f..12613962d 100644 --- a/frontend/device/sysfs_light.lua +++ b/frontend/device/sysfs_light.lua @@ -33,7 +33,7 @@ function SysfsLight:new(o) end function SysfsLight:setBrightness(brightness) - self:setNaturalBrightness(brightness, self.current_warmth) + self:setNaturalBrightness(brightness, nil) end dbg:guard(SysfsLight, 'setBrightness', @@ -43,7 +43,7 @@ dbg:guard(SysfsLight, 'setBrightness', end) function SysfsLight:setWarmth(warmth) - self:setNaturalBrightness(self.current_brightness, warmth) + self:setNaturalBrightness(nil, warmth) end dbg:guard(SysfsLight, 'setWarmth', @@ -53,10 +53,14 @@ dbg:guard(SysfsLight, 'setWarmth', end) function SysfsLight:setNaturalBrightness(brightness, warmth) + local set_brightness = true + local set_warmth = true if not brightness then + set_brightness = false brightness = self.current_brightness end if not warmth then + set_warmth = false warmth = self.current_warmth end @@ -64,12 +68,16 @@ function SysfsLight:setNaturalBrightness(brightness, warmth) if self.frontlight_mixer then -- Honor the device's scale, which may not be [0...100] (f.g., it's [0...10] on the Forma) ;). warmth = math.floor(warmth / self.nl_max) - self:_write_value(self.frontlight_white, brightness) + if set_brightness then + self:_write_value(self.frontlight_white, brightness) + end -- And it may be inverted... (cold is nl_max, warm is nl_min) - if self.nl_inverted then - self:_write_value(self.frontlight_mixer, self.nl_max - warmth) - else - self:_write_value(self.frontlight_mixer, warmth) + if set_warmth then + if self.nl_inverted then + self:_write_value(self.frontlight_mixer, self.nl_max - warmth) + else + self:_write_value(self.frontlight_mixer, warmth) + end end else local red = 0 diff --git a/frontend/ui/elements/common_settings_menu_table.lua b/frontend/ui/elements/common_settings_menu_table.lua index 3a313cd0c..c3ffc57ff 100644 --- a/frontend/ui/elements/common_settings_menu_table.lua +++ b/frontend/ui/elements/common_settings_menu_table.lua @@ -114,15 +114,18 @@ if Device:isKobo() then end, callback = function() G_reader_settings:flipNilOrFalse("ignore_power_sleepcover") + UIManager:show(InfoMessage:new{ + text = _("This will take effect on next restart."), + }) end } end common_settings.night_mode = { text = _("Night mode"), - checked_func = function() return G_reader_settings:readSetting("night_mode") end, + checked_func = function() return G_reader_settings:isTrue("night_mode") end, callback = function() - local night_mode = G_reader_settings:readSetting("night_mode") or false + local night_mode = G_reader_settings:isTrue("night_mode") Screen:toggleNightMode() UIManager:setDirty(nil, "full") G_reader_settings:saveSetting("night_mode", not night_mode) diff --git a/frontend/ui/widget/inputtext.lua b/frontend/ui/widget/inputtext.lua index c7a5da144..9b59ada99 100644 --- a/frontend/ui/widget/inputtext.lua +++ b/frontend/ui/widget/inputtext.lua @@ -53,9 +53,9 @@ local InputText = InputContainer:new{ } -- only use PhysicalKeyboard if the device does not have touch screen -if Device.isTouchDevice() or Device.hasDPad() then +if Device:isTouchDevice() or Device:hasDPad() then Keyboard = require("ui/widget/virtualkeyboard") - if Device.isTouchDevice() then + if Device:isTouchDevice() then function InputText:initEventListener() self.ges_events = { TapTextBox = { @@ -150,7 +150,7 @@ if Device.isTouchDevice() or Device.hasDPad() then end end - if Device.hasDPad() then + if Device:hasDPad() then if not InputText.initEventListener then function InputText:initEventListener() end end diff --git a/reader.lua b/reader.lua index a53a2cddc..ced1f1a5f 100755 --- a/reader.lua +++ b/reader.lua @@ -63,7 +63,7 @@ CanvasContext:init(Device) if G_reader_settings:has("color_rendering") then CanvasContext:setColorRenderingEnabled(G_reader_settings:isTrue("color_rendering")) else - CanvasContext:setColorRenderingEnabled(Device.screen.isColorScreen()) + CanvasContext:setColorRenderingEnabled(Device.screen:isColorScreen()) end -- option parsing: @@ -170,7 +170,7 @@ elseif not QuickStart:isShown() then last_file = QuickStart:getQuickStart() end -- night mode -if G_reader_settings:readSetting("night_mode") then +if G_reader_settings:isTrue("night_mode") then Device.screen:toggleNightMode() end @@ -181,7 +181,7 @@ end -- Inform once about color rendering on newly supported devices -- (there are some android devices that may not have a color screen, -- and we are not (yet?) able to guess that fact) -if Device.hasColorScreen() and not G_reader_settings:has("color_rendering") then +if Device:hasColorScreen() and not G_reader_settings:has("color_rendering") then -- enable it to prevent further display of this message G_reader_settings:saveSetting("color_rendering", true) local InfoMessage = require("ui/widget/infomessage") diff --git a/spec/unit/autofrontlight_spec.lua b/spec/unit/autofrontlight_spec.lua index a346eb627..01a3af2a7 100644 --- a/spec/unit/autofrontlight_spec.lua +++ b/spec/unit/autofrontlight_spec.lua @@ -109,6 +109,7 @@ describe("AutoFrontlight widget tests", function() end) it("should turn on frontlight at the begining", function() + Device:getPowerDevice():turnOffFrontlight() Device.brightness = 0 AutoFrontlight = class:new() MockTime:increase(2) @@ -117,6 +118,7 @@ describe("AutoFrontlight widget tests", function() end) it("should turn off frontlight at the begining", function() + Device:getPowerDevice():turnOnFrontlight() Device.brightness = 3 AutoFrontlight = class:new() MockTime:increase(2) @@ -125,6 +127,7 @@ describe("AutoFrontlight widget tests", function() end) it("should handle configuration update", function() + Device:getPowerDevice():turnOffFrontlight() Device.brightness = 0 AutoFrontlight = class:new() MockTime:increase(2) diff --git a/spec/unit/frontlight_spec.lua b/spec/unit/frontlight_spec.lua index e63e55a8b..36466ed50 100644 --- a/spec/unit/frontlight_spec.lua +++ b/spec/unit/frontlight_spec.lua @@ -1,174 +1,195 @@ describe("Frontlight function in PowerD", function() - local PowerD + local Device, PowerD local param, test_when_on, test_when_off setup(function() require("commonrequire") + package.unloadAll() + require("document/canvascontext"):init(require("device")) PowerD = require("device/generic/powerd"):new{ - frontlight = 0, + frontlight = 2, } param = { fl_min = 1, fl_max = 5, - device = { - hasFrontlight = function() return true end, - -- TODO @Frenzie remove this once possibly turning on frontlight - -- on init is Kobo-only; see device/generic/powerd 2017-10-08 - isAndroid = function() return false end, - }, + fl_intensity = 2, + device = nil, + is_fl_on = true, } - end) - before_each(function() - stub(PowerD, "init") - stub(PowerD, "frontlightIntensityHW") - stub(PowerD, "setIntensityHW") + PowerD.frontlightIntensityHW = function(self) + return self.frontlight + end PowerD.setIntensityHW = function(self, intensity) self.frontlight = intensity end + end) + + teardown(function() + package.unloadAll() + require("document/canvascontext"):init(require("device")) + end) + + before_each(function() + Device = require("device") + Device.isKobo = function() return true end + Device.model = "Kobo_dahlia" + Device.hasFrontlight = function() return true end + param.device = Device + Device.powerd = PowerD:new{ + param + } + + + stub(PowerD, "init") + spy.on(PowerD, "frontlightIntensityHW") spy.on(PowerD, "setIntensityHW") spy.on(PowerD, "turnOnFrontlightHW") spy.on(PowerD, "turnOffFrontlightHW") end) it("should read frontlight intensity during initialization", function() - PowerD.frontlightIntensityHW.returns(2) local p = PowerD:new(param) + assert.are.equal(2, p:frontlightIntensityHW()) assert.are.equal(2, p:frontlightIntensity()) assert.is.truthy(p:isFrontlightOn()) assert.stub(p.init).is_called(1) - assert.stub(p.frontlightIntensityHW).is_called(1) + assert.spy(p.frontlightIntensityHW).is_called(2) end) test_when_off = function(fl_min) param.fl_min = fl_min - PowerD.frontlightIntensityHW.returns(fl_min) + param.fl_intensity = 0 local p = PowerD:new(param) - assert.are.equal(0, p:frontlightIntensity()) + p:setIntensity(0) + assert.are.equal(param.fl_min, p:frontlightIntensityHW()) + assert.are.equal(0, p:frontlightIntensity()) -- returns 0 when off assert.is.truthy(p:isFrontlightOff()) assert.stub(p.init).is_called(1) - assert.stub(p.setIntensityHW).is_called(1) + assert.spy(p.setIntensityHW).is_called(1) assert.are.equal(param.fl_min, p.frontlight) - assert.stub(p.frontlightIntensityHW).is_called(1) + assert.spy(p.frontlightIntensityHW).is_called(2) assert.spy(p.turnOnFrontlightHW).is_called(0) - assert.spy(p.turnOffFrontlightHW).is_called(1) + assert.spy(p.turnOffFrontlightHW).is_called(0) -- The intensity is param.fl_min, turnOnFrontlight() should take no effect. assert.is.falsy(p:turnOnFrontlight()) assert.are.equal(0, p:frontlightIntensity()) assert.is.truthy(p:isFrontlightOff()) - assert.stub(p.setIntensityHW).is_called(1) + assert.spy(p.setIntensityHW).is_called(1) assert.spy(p.turnOnFrontlightHW).is_called(0) - assert.spy(p.turnOffFrontlightHW).is_called(1) + assert.spy(p.turnOffFrontlightHW).is_called(0) -- Same as the above one, toggleFrontlight() should also take no effect. assert.is.falsy(p:toggleFrontlight()) assert.are.equal(0, p:frontlightIntensity()) assert.is.truthy(p:isFrontlightOff()) - assert.stub(p.setIntensityHW).is_called(1) + assert.spy(p.setIntensityHW).is_called(1) assert.spy(p.turnOnFrontlightHW).is_called(0) - assert.spy(p.turnOffFrontlightHW).is_called(1) + assert.spy(p.turnOffFrontlightHW).is_called(0) assert.is.truthy(p:setIntensity(2)) assert.are.equal(2, p:frontlightIntensity()) assert.is.truthy(p:isFrontlightOn()) - assert.stub(p.setIntensityHW).is_called(2) + assert.spy(p.setIntensityHW).is_called(2) assert.are.equal(2, p.frontlight) assert.spy(p.turnOnFrontlightHW).is_called(0) - assert.spy(p.turnOffFrontlightHW).is_called(1) + assert.spy(p.turnOffFrontlightHW).is_called(0) assert.is.falsy(p:turnOnFrontlight()) assert.are.equal(2, p:frontlightIntensity()) assert.is.truthy(p:isFrontlightOn()) - assert.stub(p.setIntensityHW).is_called(2) + assert.spy(p.setIntensityHW).is_called(2) assert.spy(p.turnOnFrontlightHW).is_called(0) - assert.spy(p.turnOffFrontlightHW).is_called(1) + assert.spy(p.turnOffFrontlightHW).is_called(0) assert.is.truthy(p:turnOffFrontlight()) assert.are.equal(0, p:frontlightIntensity()) assert.is.truthy(p:isFrontlightOff()) - assert.stub(p.setIntensityHW).is_called(3) + assert.spy(p.setIntensityHW).is_called(3) assert.are.equal(param.fl_min, p.frontlight) assert.spy(p.turnOnFrontlightHW).is_called(0) - assert.spy(p.turnOffFrontlightHW).is_called(2) + assert.spy(p.turnOffFrontlightHW).is_called(1) assert.is.truthy(p:turnOnFrontlight()) assert.are.equal(2, p:frontlightIntensity()) assert.is.truthy(p:isFrontlightOn()) - assert.stub(p.setIntensityHW).is_called(4) + assert.spy(p.setIntensityHW).is_called(4) assert.are.equal(2, p.frontlight) assert.spy(p.turnOnFrontlightHW).is_called(1) - assert.spy(p.turnOffFrontlightHW).is_called(2) + assert.spy(p.turnOffFrontlightHW).is_called(1) assert.is.truthy(p:toggleFrontlight()) assert.are.equal(0, p:frontlightIntensity()) assert.is.truthy(p:isFrontlightOff()) - assert.stub(p.setIntensityHW).is_called(5) + assert.spy(p.setIntensityHW).is_called(5) assert.are.equal(param.fl_min, p.frontlight) assert.spy(p.turnOnFrontlightHW).is_called(1) - assert.spy(p.turnOffFrontlightHW).is_called(3) + assert.spy(p.turnOffFrontlightHW).is_called(2) assert.is.truthy(p:toggleFrontlight()) assert.are.equal(2, p:frontlightIntensity()) assert.is.truthy(p:isFrontlightOn()) - assert.stub(p.setIntensityHW).is_called(6) + assert.spy(p.setIntensityHW).is_called(6) assert.are.equal(2, p.frontlight) assert.spy(p.turnOnFrontlightHW).is_called(2) - assert.spy(p.turnOffFrontlightHW).is_called(3) + assert.spy(p.turnOffFrontlightHW).is_called(2) end test_when_on = function(fl_min) assert(fl_min < 2) param.fl_min = fl_min - PowerD.frontlightIntensityHW.returns(2) + param.fl_intensity = 2 local p = PowerD:new(param) + p:setIntensity(2) + assert.are.equal(2, p:frontlightIntensityHW()) assert.are.equal(2, p:frontlightIntensity()) assert.is.truthy(p:isFrontlightOn()) assert.stub(p.init).is_called(1) - assert.stub(p.setIntensityHW).is_called(1) + --assert.spy(p.setIntensityHW).is_called(1) assert.are.equal(2, p.frontlight) - assert.spy(p.turnOnFrontlightHW).is_called(1) + assert.spy(p.turnOnFrontlightHW).is_called(0) assert.spy(p.turnOffFrontlightHW).is_called(0) assert.is.falsy(p:setIntensity(2)) assert.are.equal(2, p:frontlightIntensity()) assert.is.truthy(p:isFrontlightOn()) - assert.stub(p.setIntensityHW).is_called(1) + --assert.spy(p.setIntensityHW).is_called(1) assert.are.equal(2, p.frontlight) - assert.spy(p.turnOnFrontlightHW).is_called(1) + assert.spy(p.turnOnFrontlightHW).is_called(0) assert.spy(p.turnOffFrontlightHW).is_called(0) assert.is.falsy(p:turnOnFrontlight()) assert.are.equal(2, p:frontlightIntensity()) assert.is.truthy(p:isFrontlightOn()) - assert.stub(p.setIntensityHW).is_called(1) + --assert.spy(p.setIntensityHW).is_called(1) assert.are.equal(2, p.frontlight) - assert.spy(p.turnOnFrontlightHW).is_called(1) + assert.spy(p.turnOnFrontlightHW).is_called(0) assert.spy(p.turnOffFrontlightHW).is_called(0) assert.is.truthy(p:turnOffFrontlight()) assert.are.equal(0, p:frontlightIntensity()) assert.is.truthy(p:isFrontlightOff()) - assert.stub(p.setIntensityHW).is_called(2) + --assert.spy(p.setIntensityHW).is_called(2) assert.are.equal(param.fl_min, p.frontlight) - assert.spy(p.turnOnFrontlightHW).is_called(1) + assert.spy(p.turnOnFrontlightHW).is_called(0) assert.spy(p.turnOffFrontlightHW).is_called(1) assert.is.truthy(p:toggleFrontlight()) assert.are.equal(2, p:frontlightIntensity()) assert.is.truthy(p:isFrontlightOn()) - assert.stub(p.setIntensityHW).is_called(3) + --assert.spy(p.setIntensityHW).is_called(3) assert.are.equal(2, p.frontlight) - assert.spy(p.turnOnFrontlightHW).is_called(2) + assert.spy(p.turnOnFrontlightHW).is_called(1) assert.spy(p.turnOffFrontlightHW).is_called(1) assert.is.truthy(p:toggleFrontlight()) assert.are.equal(0, p:frontlightIntensity()) assert.is.truthy(p:isFrontlightOff()) - assert.stub(p.setIntensityHW).is_called(4) + --assert.spy(p.setIntensityHW).is_called(4) assert.are.equal(param.fl_min, p.frontlight) - assert.spy(p.turnOnFrontlightHW).is_called(2) + assert.spy(p.turnOnFrontlightHW).is_called(1) assert.spy(p.turnOffFrontlightHW).is_called(2) end