2
0
mirror of https://github.com/koreader/koreader synced 2024-10-31 21:20:20 +00:00
koreader/frontend/device/generic/device.lua
NiLuJe 011370882f [chore] Some Wi-Fi tweaks (#4564)
* On Kobo, kill WiFi on startup if we detect an inconsistent state...

Untested, not terribly pretty.

The other solution is to slow down the Wi-Fi meny by doing the same
check for the "Wi-Fi connection" checkbox as in the later wifi_status
one...

* Don't enable auto_restore_wifi by default

It's liable to silently murder batteries for no good reason, given that
we prompt to enable WiFi by default when needed, and we otherwise have
no actual need to keep WiFi on in the background.

re #2215 (in particular, this directly contradicts @houqp in
https://github.com/koreader/koreader/pull/2215#discussion_r74696133 ;)).
2019-02-08 22:29:11 +01:00

301 lines
11 KiB
Lua

local logger = require("logger")
local _ = require("gettext")
local function yes() return true end
local function no() return false end
local Device = {
screen_saver_mode = false,
charging_mode = false,
survive_screen_saver = false,
is_cover_closed = false,
model = nil,
powerd = nil,
screen = nil,
input = nil,
-- For Kobo, wait at least 15 seconds before calling suspend script. Otherwise, suspend might
-- fail and the battery will be drained while we are in screensaver mode
suspend_wait_timeout = 15,
-- hardware feature tests: (these are functions!)
hasKeyboard = no,
hasKeys = no,
hasDPad = no,
isTouchDevice = no,
hasFrontlight = no,
needsTouchScreenProbe = no,
hasClipboard = yes, -- generic internal clipboard on all devices
hasEinkScreen = yes,
canHWDither = no,
hasColorScreen = no,
hasBGRFrameBuffer = no,
canToggleGSensor = no,
-- use these only as a last resort. We should abstract the functionality
-- and have device dependent implementations in the corresponting
-- device/<devicetype>/device.lua file
-- (these are functions!)
isAndroid = no,
isCervantes = no,
isKindle = no,
isKobo = no,
isPocketBook = no,
isSonyPRSTUX = no,
isSDL = no,
isEmulator = no,
-- some devices have part of their screen covered by the bezel
viewport = nil,
-- enforce portrait orientation on display, no matter how configured at
-- startup
isAlwaysPortrait = no,
-- needs full screen refresh when resumed from screensaver?
needsScreenRefreshAfterResume = yes,
-- set to yes on devices whose framebuffer reports 8bit per pixel,
-- but is actually a color eInk screen with 24bit per pixel.
-- The refresh is still based on bytes. (This solves issue #4193.)
has3BytesWideFrameBuffer = no,
-- set to yes on devices that support over-the-air incremental updates.
hasOTAUpdates = no,
}
function Device:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
-- Inverts PageTurn button mappings
-- NOTE: For ref. on Kobo, stored by Nickel in the [Reading] section as invertPageTurnButtons=true
function Device:invertButtons()
if self:hasKeys() and self.input and self.input.event_map then
for key, value in pairs(self.input.event_map) do
if value == "LPgFwd" then
self.input.event_map[key] = "LPgBack"
elseif value == "LPgBack" then
self.input.event_map[key] = "LPgFwd"
elseif value == "RPgFwd" then
self.input.event_map[key] = "RPgBack"
elseif value == "RPgBack" then
self.input.event_map[key] = "RPgFwd"
end
end
-- NOTE: We currently leave self.input.rotation_map alone,
-- which will definitely yield fairly stupid mappings in Landscape...
end
end
function Device:init()
assert(self ~= nil)
if not self.screen then
error("screen/framebuffer must be implemented")
end
self.screen.isColorScreen = self.hasColorScreen
self.screen.isColorEnabled = function()
if G_reader_settings:has("color_rendering") then return G_reader_settings:isTrue("color_rendering") end
return self.screen.isColorScreen()
end
self.screen.isBGRFrameBuffer = self.hasBGRFrameBuffer
local low_pan_rate = G_reader_settings:readSetting("low_pan_rate")
self.screen.low_pan_rate = (low_pan_rate == nil) or low_pan_rate
logger.info("initializing for device", self.model)
logger.info("framebuffer resolution:", self.screen:getSize())
if not self.input then
self.input = require("device/input"):new{device = self}
end
if not self.powerd then
self.powerd = require("device/generic/powerd"):new{device = self}
end
if self.viewport then
logger.dbg("setting a viewport:", self.viewport)
self.screen:setViewport(self.viewport)
self.input:registerEventAdjustHook(
self.input.adjustTouchTranslate,
{x = 0 - self.viewport.x, y = 0 - self.viewport.y})
end
-- Handle button mappings shenanigans
if self:hasKeys() then
if G_reader_settings:isTrue("input_invert_page_turn_keys") then
self:invertButtons()
end
end
end
function Device:getPowerDevice()
return self.powerd
end
function Device:rescheduleSuspend()
local UIManager = require("ui/uimanager")
UIManager:unschedule(self.suspend)
UIManager:scheduleIn(self.suspend_wait_timeout, self.suspend)
end
-- ONLY used for Kobo and PocketBook devices
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
self:rescheduleSuspend()
else
logger.dbg("Resuming...")
local UIManager = require("ui/uimanager")
UIManager:unschedule(self.suspend)
local network_manager = require("ui/network/manager")
if network_manager.wifi_was_on and G_reader_settings:isTrue("auto_restore_wifi") then
network_manager:restoreWifiAsync()
end
self:resume()
require("ui/screensaver"):close()
-- restore to previous rotation mode, if need be.
if self.orig_rotation_mode then
self.screen:setRotationMode(self.orig_rotation_mode)
end
if 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
-- Already in screen saver mode, no need to update UI/state before
-- suspending the hardware. This usually happens when sleep cover
-- is closed after the device was sent to suspend state.
logger.dbg("Already in screen saver mode, suspending...")
self:rescheduleSuspend()
end
-- else we we not in screensaver mode
elseif ev == "Power" or ev == "Suspend" then
self.powerd:beforeSuspend()
local UIManager = require("ui/uimanager")
logger.dbg("Suspending...")
-- Mostly always suspend in portrait mode...
-- ... except when we just show an InfoMessage, it plays badly with landscape mode (c.f., #4098)
if G_reader_settings:readSetting("screensaver_type") ~= "message" then
self.orig_rotation_mode = self.screen:getRotationMode()
self.screen:setRotationMode(0)
else
-- nil it, in case user switched ScreenSaver modes during our lifetime.
self.orig_rotation_mode = nil
end
require("ui/screensaver"):show()
if self:needsScreenRefreshAfterResume() then
self.screen:refreshFull()
end
self.screen_saver_mode = true
UIManager:scheduleIn(0.1, function()
local network_manager = require("ui/network/manager")
-- NOTE: wifi_was_on does not necessarily mean that WiFi is *currently* on! It means *we* enabled it.
-- This is critical on Kobos (c.f., #3936), where it might still be on from KSM or Nickel,
-- without us being aware of it (i.e., wifi_was_on still unset or false),
-- because suspend will at best fail, and at worst deadlock the system if WiFi is on,
-- regardless of who enabled it!
if network_manager.wifi_was_on or network_manager:isWifiOn() then
network_manager:releaseIP()
network_manager:turnOffWifi()
end
UIManager:scheduleIn(self.suspend_wait_timeout, self.suspend)
end)
end
end
-- Hardware specific method to handle usb plug in event
function Device:usbPlugIn() end
-- Hardware specific method to handle usb plug out event
function Device:usbPlugOut() end
-- Hardware specific method to suspend the device
function Device:suspend() end
-- Hardware specific method to resume the device
function Device:resume() end
-- Hardware specific method to power off the device
function Device:powerOff() end
-- Hardware specific method to reboot the device
function Device:reboot() end
-- Hardware specific method to initialize network manager module
function Device:initNetworkManager() end
function Device:supportsScreensaver() return false end
-- Device specific method to set datetime
function Device:setDateTime(year, month, day, hour, min, sec) end
-- Device specific method if any setting needs being saved
function Device:saveSettings() end
-- Device specific method for toggling the GSensor
function Device:toggleGSensor() end
--[[
prepare for application shutdown
--]]
function Device:exit()
require("ffi/input"):closeAll()
self.screen:close()
end
function Device:retrieveNetworkInfo()
local std_out = io.popen("ifconfig | " ..
"sed -n " ..
"-e 's/ \\+$//g' " ..
"-e 's/ \\+/ /g' " ..
"-e 's/ \\?inet6\\? addr: \\?\\([^ ]\\+\\) .*$/IP: \\1/p' " ..
"-e 's/Link encap:Ethernet\\(.*\\)/\\1/p'",
"r")
if std_out then
local result = std_out:read("*all")
std_out:close()
std_out = io.popen('2>/dev/null iwconfig | grep ESSID | cut -d\\" -f2')
if std_out then
local ssid = std_out:read("*all")
result = result .. "SSID: " .. ssid:gsub("(.-)%s*$", "%1") .. "\n"
std_out:close()
end
if os.execute("ip r | grep -q default") == 0 then
local pingok = os.execute("ping -q -w 3 -c 2 `ip r | grep default | cut -d ' ' -f 3` > /dev/null")
if pingok == 0 then
result = result .. "Gateway ping successful"
else
result = result .. "Gateway ping FAILED"
end
else
result = result .. "No default gateway to ping"
end
return result
end
end
function Device:setTime(hour, min)
return false
end
-- Return an integer value to indicate the brightness of the environment. The value should be in
-- range [0, 4].
-- 0: dark.
-- 1: dim, frontlight is needed.
-- 2: neutral, turning frontlight on or off does not impact the reading experience.
-- 3: bright, frontlight is not needed.
-- 4: dazzling.
function Device:ambientBrightnessLevel()
return 0
end
return Device