2019-09-29 13:42:05 +00:00
--[[--
Generic device abstraction .
This module defines stubs for common methods .
--]]
2016-12-29 08:10:38 +00:00
local logger = require ( " logger " )
2020-06-25 19:33:51 +00:00
local util = require ( " util " )
2016-11-16 10:49:34 +00:00
local _ = require ( " gettext " )
2020-12-10 15:59:14 +00:00
local T = require ( " ffi/util " ) . template
2014-10-30 18:42:18 +00:00
2015-09-27 01:25:47 +00:00
local function yes ( ) return true end
2014-10-30 18:42:18 +00:00
local function no ( ) return false end
local Device = {
screen_saver_mode = false ,
charging_mode = false ,
survive_screen_saver = false ,
2016-09-14 05:16:31 +00:00
is_cover_closed = false ,
2019-02-18 16:01:00 +00:00
should_restrict_JIT = false ,
2014-10-30 18:42:18 +00:00
model = nil ,
powerd = nil ,
screen = nil ,
2019-03-11 09:01:37 +00:00
screen_dpi_override = nil ,
2014-10-30 18:42:18 +00:00
input = nil ,
2020-06-19 07:41:50 +00:00
home_dir = nil ,
2016-09-19 08:16:41 +00:00
-- 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 ,
2014-10-30 18:42:18 +00:00
-- hardware feature tests: (these are functions!)
2020-07-20 22:52:50 +00:00
hasBattery = yes ,
2014-10-30 18:42:18 +00:00
hasKeyboard = no ,
hasKeys = no ,
2015-09-27 01:05:37 +00:00
hasDPad = no ,
2020-06-19 07:41:50 +00:00
hasExitOptions = yes ,
2020-05-26 15:43:44 +00:00
hasFewKeys = no ,
2019-02-06 14:51:50 +00:00
hasWifiToggle = yes ,
hasWifiManager = no ,
2019-09-29 13:42:05 +00:00
isHapticFeedbackEnabled = no ,
2014-10-30 18:42:18 +00:00
isTouchDevice = no ,
hasFrontlight = no ,
2019-04-15 18:06:24 +00:00
hasNaturalLight = no , -- FL warmth implementation specific to NTX boards (Kobo, Cervantes)
hasNaturalLightMixer = no , -- Same, but only found on newer boards
2020-08-19 20:41:10 +00:00
hasNaturalLightApi = no ,
2016-04-03 04:52:30 +00:00
needsTouchScreenProbe = no ,
2019-01-15 17:40:36 +00:00
hasClipboard = yes , -- generic internal clipboard on all devices
2019-02-01 08:18:27 +00:00
hasEinkScreen = yes ,
2020-11-27 19:51:40 +00:00
hasExternalSD = no , -- or other storage volume that cannot be accessed using the File Manager
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
2019-02-07 00:14:37 +00:00
canHWDither = no ,
2019-04-08 21:05:08 +00:00
canHWInvert = no ,
2019-05-02 02:27:48 +00:00
canUseCBB = yes , -- The C BB maintains a 1:1 feature parity with the Lua BB, except that is has NO support for BB4, and limited support for BBRGB24
2017-10-01 17:23:06 +00:00
hasColorScreen = no ,
2018-06-02 16:10:55 +00:00
hasBGRFrameBuffer = no ,
2019-12-21 14:59:23 +00:00
canImportFiles = no ,
2020-01-05 11:56:01 +00:00
canShareText = no ,
2020-07-09 17:11:44 +00:00
hasGSensor = no ,
2019-01-08 01:59:47 +00:00
canToggleGSensor = no ,
2020-07-09 17:11:44 +00:00
isGSensorLocked = no ,
2019-02-15 00:18:30 +00:00
canToggleMassStorage = no ,
2020-10-21 23:17:34 +00:00
canToggleChargingLED = no ,
2019-08-01 17:10:46 +00:00
canUseWAL = yes , -- requires mmap'ed I/O on the target FS
2019-08-20 16:38:02 +00:00
canRestart = yes ,
2020-06-19 07:41:50 +00:00
canSuspend = yes ,
2019-08-20 16:38:02 +00:00
canReboot = no ,
canPowerOff = no ,
2020-09-01 14:39:47 +00:00
canAssociateFileExtensions = no ,
2014-10-30 18:42:18 +00:00
2020-12-30 21:26:40 +00:00
-- Start and stop text input mode (e.g. open soft keyboard, etc)
startTextInput = function ( ) end ,
stopTextInput = function ( ) end ,
2014-10-30 18:42:18 +00:00
-- 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!)
2018-10-31 22:48:36 +00:00
isAndroid = no ,
isCervantes = no ,
2014-10-30 18:42:18 +00:00
isKindle = no ,
isKobo = no ,
2015-01-24 16:51:57 +00:00
isPocketBook = no ,
2020-02-08 00:58:10 +00:00
isRemarkable = no ,
2018-09-07 23:37:04 +00:00
isSonyPRSTUX = no ,
2015-10-03 06:18:47 +00:00
isSDL = no ,
2019-01-03 17:21:35 +00:00
isEmulator = no ,
2019-08-20 16:38:02 +00:00
isDesktop = no ,
2014-10-30 18:42:18 +00:00
-- some devices have part of their screen covered by the bezel
viewport = nil ,
2020-09-22 20:04:37 +00:00
-- enforce portrait orientation of display when FB defaults to landscape
2014-11-27 15:33:48 +00:00
isAlwaysPortrait = no ,
2020-09-22 20:04:37 +00:00
-- On some devices (eg newer pocketbook) we can force HW rotation on the fly (before each update)
-- The value here is table of 4 elements mapping the sensible linux constants to whatever
2020-09-27 19:35:03 +00:00
-- nonsense the device actually has. Canonically it should return { 0, 1, 2, 3 } if the device
2020-09-22 20:04:37 +00:00
-- matches <linux/fb.h> FB_ROTATE_* constants.
-- See https://github.com/koreader/koreader-base/blob/master/ffi/framebuffer.lua for full template
-- of the table expected.
2020-09-27 19:35:03 +00:00
usingForcedRotation = function ( ) return nil end ,
2015-09-27 01:25:47 +00:00
-- needs full screen refresh when resumed from screensaver?
needsScreenRefreshAfterResume = yes ,
2018-09-30 19:37:14 +00:00
2018-10-06 05:55:35 +00:00
-- set to yes on devices that support over-the-air incremental updates.
hasOTAUpdates = no ,
2019-03-20 15:58:32 +00:00
2020-09-28 23:06:41 +00:00
-- set to yes on devices that have a non-blocking isWifiOn implementation
-- (c.f., https://github.com/koreader/koreader/pull/5211#issuecomment-521304139)
hasFastWifiStatusQuery = no ,
2019-03-31 17:19:07 +00:00
canOpenLink = no ,
2019-03-20 15:58:32 +00:00
openLink = no ,
2019-07-08 12:19:36 +00:00
canExternalDictLookup = no ,
2014-10-30 18:42:18 +00:00
}
function Device : new ( o )
2016-02-16 07:10:07 +00:00
o = o or { }
2014-10-30 18:42:18 +00:00
setmetatable ( o , self )
self.__index = self
return o
end
2019-01-08 01:59:47 +00:00
-- 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
2014-10-30 18:42:18 +00:00
function Device : init ( )
2017-06-14 17:32:16 +00:00
assert ( self ~= nil )
2014-10-30 18:42:18 +00:00
if not self.screen then
2014-11-20 19:24:02 +00:00
error ( " screen/framebuffer must be implemented " )
2014-10-30 18:42:18 +00:00
end
2014-11-22 21:55:53 +00:00
2020-09-22 21:26:05 +00:00
-- opt-out of CBB if the device is broken with it
if not self.canUseCBB ( ) then
local bb = require ( " ffi/blitbuffer " )
bb.has_cblitbuffer = false
bb : enableCBB ( false )
end
2019-03-19 19:18:38 +00:00
if self.hasMultitouch == nil then
-- default to assuming multitouch when dealing with a touch device
self.hasMultitouch = self.isTouchDevice
end
2017-10-01 17:23:06 +00:00
self.screen . isColorScreen = self.hasColorScreen
2019-02-18 07:20:42 +00:00
self.screen . isColorEnabled = function ( )
if G_reader_settings : has ( " color_rendering " ) then
return G_reader_settings : isTrue ( " color_rendering " )
else
return self.screen . isColorScreen ( )
end
end
2017-09-30 22:16:38 +00:00
2018-06-02 16:10:55 +00:00
self.screen . isBGRFrameBuffer = self.hasBGRFrameBuffer
2021-03-06 21:44:18 +00:00
if G_reader_settings : has ( " low_pan_rate " ) then
self.screen . low_pan_rate = G_reader_settings : readSetting ( " low_pan_rate " )
2019-03-04 18:15:00 +00:00
else
self.screen . low_pan_rate = self.hasEinkScreen ( )
end
2016-02-29 07:08:57 +00:00
2016-12-29 08:10:38 +00:00
logger.info ( " initializing for device " , self.model )
logger.info ( " framebuffer resolution: " , self.screen : getSize ( ) )
2014-11-27 10:34:16 +00:00
2014-10-30 18:42:18 +00:00
if not self.input then
2014-11-03 09:08:55 +00:00
self.input = require ( " device/input " ) : new { device = self }
2014-10-30 18:42:18 +00:00
end
if not self.powerd then
self.powerd = require ( " device/generic/powerd " ) : new { device = self }
end
if self.viewport then
2016-12-29 08:10:38 +00:00
logger.dbg ( " setting a viewport: " , self.viewport )
2014-10-30 18:42:18 +00:00
self.screen : setViewport ( self.viewport )
self.input : registerEventAdjustHook (
self.input . adjustTouchTranslate ,
{ x = 0 - self.viewport . x , y = 0 - self.viewport . y } )
end
2019-01-08 01:59:47 +00:00
-- Handle button mappings shenanigans
if self : hasKeys ( ) then
if G_reader_settings : isTrue ( " input_invert_page_turn_keys " ) then
self : invertButtons ( )
end
end
2020-07-09 17:11:44 +00:00
-- Honor the gyro lock
if self : hasGSensor ( ) then
if G_reader_settings : isTrue ( " input_lock_gsensor " ) then
self : lockGSensor ( true )
end
end
2014-10-30 18:42:18 +00:00
end
2019-03-05 08:51:00 +00:00
function Device : setScreenDPI ( dpi_override )
2020-12-13 00:41:44 +00:00
-- Passing a nil resets to defaults and clears the override flag
2019-03-05 08:51:00 +00:00
self.screen : setDPI ( dpi_override )
self.input . gesture_detector : init ( )
end
2014-10-30 18:42:18 +00:00
function Device : getPowerDevice ( )
return self.powerd
end
2016-09-19 08:16:41 +00:00
function Device : rescheduleSuspend ( )
2016-09-14 05:16:31 +00:00
local UIManager = require ( " ui/uimanager " )
2016-09-19 08:16:41 +00:00
UIManager : unschedule ( self.suspend )
UIManager : scheduleIn ( self.suspend_wait_timeout , self.suspend )
2016-09-14 05:16:31 +00:00
end
2020-10-09 17:23:57 +00:00
-- Only used on platforms where we handle suspend ourselves.
2014-10-30 18:42:18 +00:00
function Device : onPowerEvent ( ev )
2021-03-06 21:44:18 +00:00
local Screensaver = require ( " ui/screensaver " )
2016-09-11 00:33:21 +00:00
if self.screen_saver_mode then
if ev == " Power " or ev == " Resume " then
2016-09-14 05:16:31 +00:00
if self.is_cover_closed then
-- don't let power key press wake up device when the cover is in closed state
2016-09-19 08:16:41 +00:00
self : rescheduleSuspend ( )
2016-09-14 05:16:31 +00:00
else
2016-12-29 08:10:38 +00:00
logger.dbg ( " Resuming... " )
2016-09-27 07:18:47 +00:00
local UIManager = require ( " ui/uimanager " )
UIManager : unschedule ( self.suspend )
2020-10-09 17:23:57 +00:00
if self : hasWifiManager ( ) and not self : isEmulator ( ) then
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 ( )
network_manager : scheduleConnectivityCheck ( )
end
2016-09-14 05:16:31 +00:00
end
self : resume ( )
2020-01-23 19:08:51 +00:00
-- Restore to previous rotation mode, if need be.
2018-07-25 22:46:52 +00:00
if self.orig_rotation_mode then
self.screen : setRotationMode ( self.orig_rotation_mode )
end
2021-03-06 21:44:18 +00:00
Screensaver : close ( )
2016-09-14 05:16:31 +00:00
if self : needsScreenRefreshAfterResume ( ) then
2016-09-27 07:18:47 +00:00
UIManager : scheduleIn ( 1 , function ( ) self.screen : refreshFull ( ) end )
2016-09-14 05:16:31 +00:00
end
self.screen_saver_mode = false
self.powerd : afterResume ( )
2016-09-11 00:33:21 +00:00
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.
2016-12-29 08:10:38 +00:00
logger.dbg ( " Already in screen saver mode, suspending... " )
2016-09-19 08:16:41 +00:00
self : rescheduleSuspend ( )
2016-09-11 00:33:21 +00:00
end
2019-02-14 19:23:28 +00:00
-- else we were not in screensaver mode
2016-09-11 00:33:21 +00:00
elseif ev == " Power " or ev == " Suspend " then
2016-02-26 09:46:23 +00:00
self.powerd : beforeSuspend ( )
2014-10-30 18:42:18 +00:00
local UIManager = require ( " ui/uimanager " )
2016-12-29 08:10:38 +00:00
logger.dbg ( " Suspending... " )
2021-03-06 21:44:18 +00:00
-- Let Screensaver set its widget up, so we get accurate info down the line in case fallbacks kick in...
Screensaver : setup ( )
2020-01-23 19:08:51 +00:00
-- Mostly always suspend in Portrait/Inverted Portrait mode...
2020-03-08 07:46:46 +00:00
-- ... except when we just show an InfoMessage or when the screensaver
2020-06-21 14:27:43 +00:00
-- is disabled, as it plays badly with Landscape mode (c.f., #4098 and #5290).
-- We also exclude full-screen widgets that work fine in Landscape mode,
-- like ReadingProgress and BookStatus (c.f., #5724)
2021-03-06 21:44:18 +00:00
if Screensaver : modeExpectsPortrait ( ) then
2018-07-25 22:46:52 +00:00
self.orig_rotation_mode = self.screen : getRotationMode ( )
2020-01-23 19:08:51 +00:00
-- Leave Portrait & Inverted Portrait alone, that works just fine.
if bit.band ( self.orig_rotation_mode , 1 ) == 1 then
-- i.e., only switch to Portrait if we're currently in *any* Landscape orientation (odd number)
2020-07-09 17:11:44 +00:00
self.screen : setRotationMode ( self.screen . ORIENTATION_PORTRAIT )
2020-01-23 19:08:51 +00:00
else
self.orig_rotation_mode = nil
end
2019-02-14 19:23:28 +00:00
-- On eInk, if we're using a screensaver mode that shows an image,
-- flash the screen to white first, to eliminate ghosting.
2021-03-06 21:44:18 +00:00
if self : hasEinkScreen ( ) and Screensaver : modeIsImage ( ) then
if Screensaver : withBackground ( ) then
2019-03-27 21:50:44 +00:00
self.screen : clear ( )
2019-03-14 19:58:45 +00:00
end
2019-02-14 19:23:28 +00:00
self.screen : refreshFull ( )
end
2018-07-25 22:46:52 +00:00
else
-- nil it, in case user switched ScreenSaver modes during our lifetime.
self.orig_rotation_mode = nil
end
2021-03-06 21:44:18 +00:00
Screensaver : show ( )
2020-10-09 17:23:57 +00:00
-- NOTE: show() will return well before the refresh ioctl is even *sent*:
-- the only thing it's done is *enqueued* the refresh in UIManager's stack.
-- Which is why the actual suspension needs to be delayed by suspend_wait_timeout,
-- otherwise, we'd potentially suspend (or attempt to) too soon.
-- On platforms where suspension is done via a sysfs knob, that'd translate to a failed suspend,
-- and on platforms where we defer to a system tool, it'd probably suspend too early!
-- c.f., #6676
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
2019-02-07 00:14:37 +00:00
if self : needsScreenRefreshAfterResume ( ) then
self.screen : refreshFull ( )
end
2016-02-26 09:46:23 +00:00
self.screen_saver_mode = true
2017-04-01 19:24:15 +00:00
UIManager : scheduleIn ( 0.1 , function ( )
2020-10-09 17:23:57 +00:00
-- NOTE: This side of the check needs to be laxer, some platforms can handle Wi-Fi without WifiManager ;).
if self : hasWifiToggle ( ) then
local network_manager = require ( " ui/network/manager " )
-- NOTE: wifi_was_on does not necessarily mean that Wi-Fi 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 Wi-Fi is on,
-- regardless of who enabled it!
if network_manager : isWifiOn ( ) then
network_manager : releaseIP ( )
network_manager : turnOffWifi ( )
end
end
UIManager : scheduleIn ( self.suspend_wait_timeout , self.suspend )
2017-04-01 19:24:15 +00:00
end )
2014-10-30 18:42:18 +00:00
end
end
2020-08-26 07:13:19 +00:00
function Device : showLightDialog ( )
local FrontLightWidget = require ( " ui/widget/frontlightwidget " )
local UIManager = require ( " ui/uimanager " )
UIManager : show ( FrontLightWidget : new { } )
end
2020-06-19 07:41:50 +00:00
function Device : info ( )
return self.model
end
2020-09-01 15:52:16 +00:00
-- Hardware specific method to track opened/closed books (nil on book close)
function Device : notifyBookState ( title , document ) end
2020-08-30 13:01:56 +00:00
-- Hardware specific method for UI to signal allowed/disallowed standby.
-- The device is allowed to enter standby only from within waitForEvents,
-- and only if allowed state is true at the time of waitForEvents() invocation.
function Device : setAutoStandby ( isAllowed ) end
2020-09-01 14:39:47 +00:00
-- Hardware specific method to set OS-level file associations to launch koreader. Expects boolean map.
function Device : associateFileExtensions ( exts )
logger.dbg ( " Device:associateFileExtensions(): " , util.tableSize ( exts ) , " entries, OS handler missing " )
end
2016-10-22 07:04:37 +00:00
-- 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
2016-03-07 08:02:15 +00:00
-- Hardware specific method to suspend the device
2016-02-26 09:46:23 +00:00
function Device : suspend ( ) end
2014-10-30 18:42:18 +00:00
2016-03-07 08:02:15 +00:00
-- Hardware specific method to resume the device
2016-02-26 09:46:23 +00:00
function Device : resume ( ) end
2014-10-30 18:42:18 +00:00
2016-04-26 22:30:52 +00:00
-- Hardware specific method to power off the device
function Device : powerOff ( ) end
2017-05-14 16:43:08 +00:00
-- Hardware specific method to reboot the device
function Device : reboot ( ) end
2016-06-12 18:50:30 +00:00
-- Hardware specific method to initialize network manager module
2016-10-22 07:04:37 +00:00
function Device : initNetworkManager ( ) end
2016-06-12 18:50:30 +00:00
2017-04-13 17:55:31 +00:00
function Device : supportsScreensaver ( ) return false end
2017-09-23 21:58:34 +00:00
-- Device specific method to set datetime
function Device : setDateTime ( year , month , day , hour , min , sec ) end
2017-09-04 19:05:05 +00:00
-- Device specific method if any setting needs being saved
function Device : saveSettings ( ) end
2020-07-20 20:37:00 +00:00
-- Simulates suspend/resume
function Device : simulateSuspend ( ) end
function Device : simulateResume ( ) end
2019-09-29 13:42:05 +00:00
--[[--
Device specific method for performing haptic feedback .
@ string type Type of haptic feedback . See < https : // developer.android . com / reference / android / view / HapticFeedbackConstants.html > .
--]]
function Device : performHapticFeedback ( type ) end
2020-06-13 10:57:08 +00:00
-- Device specific method for toggling input events
function Device : setIgnoreInput ( enable ) return true end
2019-01-08 01:59:47 +00:00
-- Device specific method for toggling the GSensor
2019-07-01 15:12:24 +00:00
function Device : toggleGSensor ( toggle ) end
2019-01-08 01:59:47 +00:00
2020-07-09 17:11:44 +00:00
-- Whether or not the GSensor should be locked to the current orientation (i.e. Portrait <-> Inverted Portrait or Landscape <-> Inverted Landscape only)
function Device : lockGSensor ( toggle )
if not self : hasGSensor ( ) then
return
end
if toggle == true then
-- Lock GSensor to current roientation
self.isGSensorLocked = yes
elseif toggle == false then
-- Unlock GSensor
self.isGSensorLocked = no
else
-- Toggle it
if self : isGSensorLocked ( ) then
self.isGSensorLocked = no
else
self.isGSensorLocked = yes
end
end
end
2020-10-21 23:17:34 +00:00
-- Device specific method for toggling the charging LED
function Device : toggleChargingLED ( toggle ) end
2014-10-30 18:42:18 +00:00
--[[
prepare for application shutdown
--]]
function Device : exit ( )
self.screen : close ( )
2020-09-22 20:04:37 +00:00
require ( " ffi/input " ) : closeAll ( )
2014-10-30 18:42:18 +00:00
end
2016-07-27 04:32:13 +00:00
function Device : retrieveNetworkInfo ( )
local std_out = io.popen ( " ifconfig | " ..
" sed -n " ..
" -e 's/ \\ +$//g' " ..
" -e 's/ \\ +/ /g' " ..
2016-12-04 14:23:57 +00:00
" -e 's/ \\ ?inet6 \\ ? addr: \\ ? \\ ([^ ] \\ + \\ ) .*$/IP: \\ 1/p' " ..
" -e 's/Link encap:Ethernet \\ (.* \\ )/ \\ 1/p' " ,
2016-07-27 04:32:13 +00:00
" r " )
if std_out then
local result = std_out : read ( " *all " )
std_out : close ( )
2018-05-01 12:49:37 +00:00
std_out = io.popen ( ' 2>/dev/null iwconfig | grep ESSID | cut -d \\ " -f2 ' )
2016-12-04 14:23:57 +00:00
if std_out then
local ssid = std_out : read ( " *all " )
2020-09-30 17:56:56 +00:00
result = result .. " SSID: " .. util.trim ( ssid ) .. " \n "
2016-12-04 14:23:57 +00:00
std_out : close ( )
end
if os.execute ( " ip r | grep -q default " ) == 0 then
2019-06-05 19:36:38 +00:00
-- NOTE: No -w flag available in the old busybox build used on Legacy Kindles...
local pingok
if self : isKindle ( ) and self : hasKeyboard ( ) then
2019-06-28 16:57:20 +00:00
pingok = os.execute ( " ping -q -c 2 `ip r | grep default | tail -n 1 | cut -d ' ' -f 3` > /dev/null " )
2019-06-05 19:36:38 +00:00
else
2019-06-28 16:57:20 +00:00
pingok = os.execute ( " ping -q -w 3 -c 2 `ip r | grep default | tail -n 1 | cut -d ' ' -f 3` > /dev/null " )
2019-06-05 19:36:38 +00:00
end
2016-12-04 14:23:57 +00:00
if pingok == 0 then
2017-03-25 21:07:47 +00:00
result = result .. " Gateway ping successful "
2016-12-04 14:23:57 +00:00
else
result = result .. " Gateway ping FAILED "
end
else
result = result .. " No default gateway to ping "
end
2016-07-27 04:32:13 +00:00
return result
end
end
2017-08-15 17:54:02 +00:00
function Device : setTime ( hour , min )
return false
end
2017-06-14 17:32:16 +00:00
-- Return an integer value to indicate the brightness of the environment. The value should be in
2017-06-24 07:55:31 +00:00
-- range [0, 4].
2017-06-14 17:32:16 +00:00
-- 0: dark.
-- 1: dim, frontlight is needed.
2017-06-24 07:55:31 +00:00
-- 2: neutral, turning frontlight on or off does not impact the reading experience.
-- 3: bright, frontlight is not needed.
-- 4: dazzling.
2017-06-14 17:32:16 +00:00
function Device : ambientBrightnessLevel ( )
return 0
end
2020-06-25 19:33:51 +00:00
--- Returns true if the file is a script we allow running
--- Basically a helper method to check a specific list of file extensions for executable scripts
---- @string filename
---- @treturn boolean
function Device : canExecuteScript ( file )
local file_ext = string.lower ( util.getFileNameSuffix ( file ) )
if file_ext == " sh " or file_ext == " py " then
return true
end
end
2020-11-10 14:00:56 +00:00
function Device : isValidPath ( path )
return util.pathExists ( path )
end
2020-11-28 21:48:09 +00:00
-- Device specific method to check if the startup script has been updated
function Device : isStartupScriptUpToDate ( )
return true
end
2020-12-10 15:59:14 +00:00
--- Unpack an archive.
-- Extract the contents of an archive, detecting its format by
-- filename extension. Inspired by luarocks archive_unpack()
-- @param archive string: Filename of archive.
-- @param extract_to string: Destination directory.
-- @return boolean or (boolean, string): true on success, false and an error message on failure.
function Device : unpackArchive ( archive , extract_to )
require ( " dbg " ) . dassert ( type ( archive ) == " string " )
local BD = require ( " ui/bidi " )
local ok
if archive : match ( " %.tar%.bz2$ " ) or archive : match ( " %.tar%.gz$ " ) or archive : match ( " %.tar%.lz$ " ) or archive : match ( " %.tgz$ " ) then
ok = self : untar ( archive , extract_to )
else
return false , T ( _ ( " Couldn't extract archive: \n \n %1 \n \n Unrecognized filename extension. " ) , BD.filepath ( archive ) )
end
if not ok then
return false , T ( _ ( " Extracting archive failed: \n \n %1 " ) , BD.filepath ( archive ) )
end
return true
end
function Device : untar ( archive , extract_to )
return os.execute ( ( " ./tar xf %q -C %q " ) : format ( archive , extract_to ) )
end
2014-10-30 18:42:18 +00:00
return Device