Koreader Ubuntu-touch port

Currently only tested on Ubuntu-touch emulator with framework
ubuntu-sdk-14.10 for armhf.
The ubuntu-touch port is binary compatible with the Kobo port
major changes in this PR are:
1. rename the emulator device to sdl device since both the emulator
and the ubuntu-touch target use libsdl to handle input/output.
2. ubuntu-touch app has no write access to the installation dir so
all write-outs should be in a seperate dir definded in `datastorage`.
pull/1660/head
chrox 9 years ago
parent c44d9fa595
commit a60544b1ad

16
.gitignore vendored

@ -19,6 +19,7 @@ emu
koreader-*.zip
koreader-*.apk
koreader-*.tar.gz
koreader-*.click
l10n/*
!l10n/Makefile
@ -27,11 +28,12 @@ l10n/*
/.cproject
/.project
koreader-arm-linux-androideabi
koreader-arm-linux-gnueabi
koreader-arm-linux-gnueabihf
koreader-i686-w64-mingw32
koreader-x86_64-linux-gnu
koreader-x86_64-pc-linux-gnu
koreader-arm-obreey-linux-gnueabi
koreader-android-arm-linux-androideabi
koreader-kindle-arm-linux-gnueabi
koreader-kobo-arm-linux-gnueabihf
koreader-emulator-i686-w64-mingw32
koreader-emulator-x86_64-linux-gnu
koreader-emulator-x86_64-pc-linux-gnu
koreader-pocketbook-arm-obreey-linux-gnueabi
koreader-ubuntu-touch-arm-linux-gnueabihf

3
.gitmodules vendored

@ -4,3 +4,6 @@
[submodule "platform/android/luajit-launcher"]
path = platform/android/luajit-launcher
url = https://github.com/koreader/android-luajit-launcher.git
[submodule "platform/ubuntu-touch/ubuntu-touch-sdl"]
path = platform/ubuntu-touch/ubuntu-touch-sdl
url = https://github.com/Sturmflut/ubuntu-touch-sdl-template

@ -17,15 +17,24 @@ else ifeq ($(TARGET), pocketbook)
endif
MACHINE?=$(shell PATH=$(PATH) $(CC) -dumpmachine 2>/dev/null)
INSTALL_DIR=koreader-$(MACHINE)
ifdef TARGET
DIST:=$(TARGET)
else
DIST:=emulator
endif
INSTALL_DIR=koreader-$(DIST)-$(MACHINE)
# platform directories
PLATFORM_DIR=platform
KINDLE_DIR=$(PLATFORM_DIR)/kindle
KOBO_DIR=$(PLATFORM_DIR)/kobo
POCKETBOOK_DIR=$(PLATFORM_DIR)/pocketbook
UBUNTUTOUCH_DIR=$(PLATFORM_DIR)/ubuntu-touch
ANDROID_DIR=$(PLATFORM_DIR)/android
ANDROID_LAUNCHER_DIR:=$(ANDROID_DIR)/luajit-launcher
UBUNTUTOUCH_SDL_DIR:=$(UBUNTUTOUCH_DIR)/ubuntu-touch-sdl
WIN32_DIR=$(PLATFORM_DIR)/win32
# files to link from main directory
@ -221,6 +230,46 @@ pbupdate: all
tar czafh ../../koreader-pocketbook-$(MACHINE)-$(VERSION).targz \
-T koreader/ota/package.index --no-recursion
utupdate: all
# ensure that the binaries were built for ARM
file $(INSTALL_DIR)/koreader/luajit | grep ARM || exit 1
# remove old package if any
rm -f koreader-ubuntu-touch-$(MACHINE)-$(VERSION).click
ln -sf ../../$(UBUNTUTOUCH_DIR)/koreader.sh $(INSTALL_DIR)/koreader
ln -sf ../../$(UBUNTUTOUCH_DIR)/manifest.json $(INSTALL_DIR)/koreader
ln -sf ../../$(UBUNTUTOUCH_DIR)/koreader.apparmor $(INSTALL_DIR)/koreader
ln -sf ../../$(UBUNTUTOUCH_DIR)/koreader.desktop $(INSTALL_DIR)/koreader
ln -sf ../../$(UBUNTUTOUCH_DIR)/koreader.png $(INSTALL_DIR)/koreader
ln -sf ../../../$(UBUNTUTOUCH_SDL_DIR)/lib/arm-linux-gnueabihf/libSDL2.so $(INSTALL_DIR)/koreader/libs
# create new package
cd $(INSTALL_DIR) && pwd && \
zip -9 -r \
../koreader-$(DIST)-$(MACHINE)-$(VERSION).zip \
koreader -x "koreader/resources/fonts/*" "koreader/ota/*" \
"koreader/resources/icons/src/*" "koreader/spec/*"
# generate update package index file
zipinfo -1 koreader-$(DIST)-$(MACHINE)-$(VERSION).zip > \
$(INSTALL_DIR)/koreader/ota/package.index
echo "koreader/ota/package.index" >> $(INSTALL_DIR)/koreader/ota/package.index
# update index file in zip package
cd $(INSTALL_DIR) && zip -u ../koreader-$(DIST)-$(MACHINE)-$(VERSION).zip \
koreader/ota/package.index
# make gzip update for zsync OTA update
cd $(INSTALL_DIR) && \
tar czafh ../koreader-$(DIST)-$(MACHINE)-$(VERSION).targz \
-T koreader/ota/package.index --no-recursion
# generate ubuntu touch click package
rm -rf $(INSTALL_DIR)/tmp && mkdir -p $(INSTALL_DIR)/tmp
cd $(INSTALL_DIR)/tmp && \
unzip ../../koreader-$(DIST)-$(MACHINE)-$(VERSION).zip && \
click build koreader && \
mv *.click ../../koreader-$(DIST)-$(MACHINE)-$(VERSION).click
androidupdate: all
mkdir -p $(ANDROID_LAUNCHER_DIR)/assets/module
-rm $(ANDROID_LAUNCHER_DIR)/assets/module/koreader-*
@ -231,6 +280,19 @@ androidupdate: all
cp $(ANDROID_LAUNCHER_DIR)/bin/NativeActivity-debug.apk \
koreader-android-$(MACHINE)-$(VERSION).apk
update:
ifeq ($(TARGET), kindle)
make kindleupdate
else ifeq ($(TARGET), kobo)
make koboupdate
else ifeq ($(TARGET), pocketbook)
make pbupdate
else ifeq ($(TARGET), ubuntu-touch)
make utupdate
else ifeq ($(TARGET), android)
make androidupdate
endif
androiddev: androidupdate
$(MAKE) -C $(ANDROID_LAUNCHER_DIR) dev

@ -75,7 +75,7 @@ and cross compiling.
Users of Debian and Ubuntu can install the required packages using:
```
sudo apt-get install build-essential libtool gcc-multilib libffi-dev \
sudo apt-get install build-essential libtool gcc-multilib libffi-dev linux-libc-dev:i386 \
patch wget unzip git autoconf subversion cmake nasm libsdl1.2-dev luarocks
```

@ -1,14 +1,38 @@
-- need low-level mechnism to detect android to avoid recursive dependency
local isAndroid = pcall(require, "android")
local lfs = require("libs/libkoreader-lfs")
local DataStorage = {}
function DataStorage:getDataDir()
local data_dir
if isAndroid then
return "/sdcard/koreader/"
data_dir = "/sdcard/koreader/"
elseif os.getenv("UBUNTU_APPLICATION_ISOLATION") then
local app_id = os.getenv("APP_ID")
local package_name = app_id:match("^(.-)_")
-- confinded ubuntu app has write access to this dir
data_dir = os.getenv("XDG_DATA_HOME") .. "/" .. package_name
else
return "./"
data_dir = "./"
end
if lfs.attributes(data_dir, "mode") ~= "directory" then
lfs.mkdir(data_dir)
end
return data_dir
end
local function initDataDir()
local data_dir = DataStorage:getDataDir()
local sub_data_dirs = {"cache", "clipboard", "data", "history", "ota", "screenshots"}
for _, dir in ipairs(sub_data_dirs) do
local sub_data_dir = data_dir .. "/" .. dir
if lfs.attributes(sub_data_dir, "mode") ~= "directory" then
lfs.mkdir(sub_data_dir)
end
end
end
initDataDir()
return DataStorage

@ -2,13 +2,14 @@ local InputContainer = require("ui/widget/container/inputcontainer")
local CenterContainer = require("ui/widget/container/centercontainer")
local ButtonDialog = require("ui/widget/buttondialog")
local lfs = require("libs/libkoreader-lfs")
local DataStorage = require("datastorage")
local UIManager = require("ui/uimanager")
local DocSettings = require("docsettings")
local Menu = require("ui/widget/menu")
local Screen = require("device").screen
local _ = require("gettext")
local history_dir = "./history/"
local history_dir = DataStorage:getDataDir() .. "/history/"
local FileManagerHistory = InputContainer:extend{
hist_menu_title = _("History"),

@ -1,6 +1,7 @@
local InputContainer = require("ui/widget/container/inputcontainer")
local DictQuickLookup = require("ui/widget/dictquicklookup")
local InfoMessage = require("ui/widget/infomessage")
local DataStorage = require("datastorage")
local UIManager = require("ui/uimanager")
local Screen = require("device").screen
local Device = require("device")
@ -15,11 +16,8 @@ local ReaderDictionary = InputContainer:new{
function ReaderDictionary:init()
self.ui.menu:registerToMainMenu(self)
if Device:isAndroid() then
self.data_dir = "/sdcard/koreader/data/dict"
else
self.data_dir = os.getenv("STARDICT_DATA_DIR") or "data/dict"
end
self.data_dir = os.getenv("STARDICT_DATA_DIR") or
DataStorage:getDataDir() .. "/data/dict"
end
function ReaderDictionary:addToMainMenu(tab_item_table)

@ -1,15 +1,18 @@
local InputContainer = require("ui/widget/container/inputcontainer")
local Device = require("device")
local Screen = require("device").screen
local InfoMessage = require("ui/widget/infomessage")
local GestureRange = require("ui/gesturerange")
local DataStorage = require("datastorage")
local UIManager = require("ui/uimanager")
local InfoMessage = require("ui/widget/infomessage")
local Device = require("device")
local Screen = require("device").screen
local DEBUG = require("dbg")
local T = require("ffi/util").template
local _ = require("gettext")
local screenshots_dir = DataStorage:getDataDir() .. "/screenshots/"
local ReaderScreenshot = InputContainer:new{
datetime_name = "screenshots/Screenshot_%Y-%b-%d_%H%M%S.png",
datetime_name = screenshots_dir .. "Screenshot_%Y-%b-%d_%H%M%S.png",
}
function ReaderScreenshot:init()

@ -3,6 +3,7 @@ A global LRU cache
]]--
local md5 = require("MD5")
local lfs = require("libs/libkoreader-lfs")
local DataStorage = require("datastorage")
local DEBUG = require("dbg")
local function calcFreeMem()
@ -30,7 +31,7 @@ local function calcCacheMemSize()
return math.min(max, math.max(min, calc))
end
local cache_path = lfs.currentdir().."/cache/"
local cache_path = DataStorage:getDataDir() .. "/cache/"
--[[
-- return a snapshot of disk cached items for subsequent check

@ -39,8 +39,10 @@ end
function Dbg:logEv(ev)
local log = ev.type.."|"..ev.code.."|"
..ev.value.."|"..ev.time.sec.."|"..ev.time.usec.."\n"
self.ev_log:write(log)
self.ev_log:flush()
if self.ev_log then
self.ev_log:write(log)
self.ev_log:flush()
end
end
function Dbg:traceback()

@ -2,8 +2,8 @@ local isAndroid, android = pcall(require, "android")
local util = require("ffi/util")
local function probeDevice()
if util.isEmulated() then
return require("device/emulator/device")
if util.isSDL() then
return require("device/sdl/device")
end
if isAndroid then

@ -29,7 +29,7 @@ local Device = {
isKobo = no,
isPocketBook = no,
isAndroid = no,
isEmulator = no,
isSDL = no,
-- some devices have part of their screen covered by the bezel
viewport = nil,

@ -6,8 +6,8 @@ local function yes() return true end
local function no() return false end
local Device = Generic:new{
model = "Emulator",
isEmulator = yes,
model = "SDL",
isSDL = yes,
hasKeyboard = yes,
hasKeys = yes,
hasDPad = yes,
@ -32,13 +32,13 @@ function Device:init()
self.screen = require("ffi/framebuffer_SDL2_0"):new{device = self, debug = DEBUG}
self.input = require("device/input"):new{
device = self,
event_map = require("device/emulator/event_map_sdl2"),
event_map = require("device/sdl/event_map_sdl2"),
}
else
self.screen = require("ffi/framebuffer_SDL1_2"):new{device = self, debug = DEBUG}
self.input = require("device/input"):new{
device = self,
event_map = require("device/emulator/event_map_sdl"),
event_map = require("device/sdl/event_map_sdl"),
}
end

@ -1,10 +1,13 @@
local lfs = require("libs/libkoreader-lfs")
local DocSettings = {}
local dump = require("dump")
local DataStorage = require("datastorage")
local dump = require("dump")
local DocSettings = {}
local history_dir = DataStorage:getDataDir() .. "/history/"
function DocSettings:getHistoryPath(fullpath)
return "./history/[" .. fullpath:gsub("(.*/)([^/]+)","%1] %2"):gsub("/","#") .. ".lua"
return history_dir .. "[" .. fullpath:gsub("(.*/)([^/]+)","%1] %2"):gsub("/","#") .. ".lua"
end
function DocSettings:getPathFromHistory(hist_name)
@ -29,9 +32,6 @@ function DocSettings:open(docfile)
-- we handle reader setting as special case
history_path = DataStorage:getDataDir() .. "/settings.reader.lua"
else
if lfs.attributes("./history", "mode") ~= "directory" then
lfs.mkdir("history")
end
history_path = self:getHistoryPath(docfile)
local sidecar = docfile:match("(.*)%.")..".sdr"

@ -3,6 +3,7 @@ local Document = require("document/document")
local Configurable = require("configurable")
local Blitbuffer = require("ffi/blitbuffer")
local lfs = require("libs/libkoreader-lfs")
local DataStorage = require("datastorage")
local Geom = require("ui/geometry")
local Device = require("device")
local Screen = require("device").screen
@ -44,7 +45,7 @@ function CreDocument:cacheInit()
if lfs.attributes("./cr3cache", "mode") == "directory" then
os.execute("rm -r ./cr3cache")
end
cre.initCache("./cache/cr3cache", 1024*1024*32)
cre.initCache(DataStorage:getDataDir() .. "/cache/cr3cache", 1024*1024*32)
end
function CreDocument:engineInit()

@ -2,6 +2,7 @@
simple serialization function, won't do uservalues, functions, loops
]]
local isUbuntuTouch = os.getenv("UBUNTU_APPLICATION_ISOLATION") ~= nil
local insert = table.insert
local function _serialize(what, outt, indent, max_lv, history)
@ -45,7 +46,17 @@ local function _serialize(what, outt, indent, max_lv, history)
insert(outt, "}")
elseif type(what) == "string" then
insert(outt, string.format("%q", what))
elseif type(what) == "number" or type(what) == "boolean" then
elseif type(what) == "number" then
if isUbuntuTouch then
-- FIXME: the `SDL_CreateRenderer` function in Ubuntu touch somehow
-- use a strange locale that formats number like this: 1.10000000000000g+02
-- which cannot be recognized by loadfile after the number is dumped.
-- Here the workaround is to preserve enough precision in "%.13e" format.
insert(outt, string.format("%.13e", what))
else
insert(outt, tostring(what))
end
elseif type(what) == "boolean" then
insert(outt, tostring(what))
elseif type(what) == "function" then
insert(outt, "nil --[[ FUNCTION ]]")

@ -2,12 +2,15 @@ local InfoMessage = require("ui/widget/infomessage")
local ConfirmBox = require("ui/widget/confirmbox")
local NetworkMgr = require("ui/networkmgr")
local lfs = require("libs/libkoreader-lfs")
local DataStorage = require("datastorage")
local UIManager = require("ui/uimanager")
local Device = require("device")
local DEBUG = require("dbg")
local T = require("ffi/util").template
local _ = require("gettext")
local ota_dir = DataStorage:getDataDir() .. "/ota/"
local OTAManager = {
ota_servers = {
"http://vislab.bjmu.edu.cn:80/apps/koreader/ota/",
@ -19,9 +22,9 @@ local OTAManager = {
"nightly",
},
zsync_template = "koreader-%s-latest-%s.zsync",
installed_package = "ota/koreader.installed.tar",
installed_package = ota_dir .. "/koreader.installed.tar",
package_indexfile = "ota/package.index",
updated_package = "ota/koreader.updated.tar",
updated_package = ota_dir .. "/koreader.updated.tar",
}
local ota_channels = {
@ -69,7 +72,7 @@ function OTAManager:checkUpdate()
local zsync_file = self:getZsyncFilename()
local ota_zsync_file = self:getOTAServer() .. zsync_file
local local_zsync_file = "ota/" .. zsync_file
local local_zsync_file = ota_dir .. zsync_file
-- download zsync file from OTA server
DEBUG("downloading zsync file", ota_zsync_file)
local r, c, h = http.request{
@ -146,7 +149,7 @@ function OTAManager:fetchAndProcessUpdate()
UIManager:show(ConfirmBox:new{
text = _("Error updating KOReader. Would you like to delete temporary files?"),
ok_callback = function()
os.execute("rm ota/ko*")
os.execute("rm " .. ota_dir .. "/ko*")
end,
})
end
@ -172,7 +175,7 @@ function OTAManager:zsync()
return os.execute(string.format(
"./zsync -i %s -o %s -u %s %s",
self.installed_package, self.updated_package,
self:getOTAServer(), "ota/" .. self:getZsyncFilename()
self:getOTAServer(), ota_dir .. self:getZsyncFilename()
))
end
end

@ -0,0 +1,15 @@
{
"policy_groups": [
"networking"
],
"read_path": [
"@{HOME}/",
"/media/*/*/[Dd][Oo][Cc][Uu][Mm][Ee][Nn][Tt][Ss]/",
"@{PROC}/*/mounts",
"/dev/disk/by-label/"
],
"write_path": [
"@{HOME}/"
],
"policy_version": 1.2
}

@ -0,0 +1,10 @@
[Desktop Entry]
Name=Koreader
Comment=Koreader for Ubuntu touch
Exec=koreader.sh
Icon=koreader.png
Terminal=false
Type=Application
MimeType=application/pdf;application/epub+zip
X-Ubuntu-Touch=true
X-Ubuntu-Supported-Orientations=portrait

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

@ -0,0 +1,31 @@
#!/bin/sh
export LC_ALL="en_US.UTF-8"
# working directory of koreader
KOREADER_DIR="${0%/*}"
# update to new version from OTA directory
NEWUPDATE="${KOREADER_DIR}/ota/koreader.updated.tar"
INSTALLED="${KOREADER_DIR}/ota/koreader.installed.tar"
if [ -f $NEWUPDATE ]; then
# TODO: any graphic indication for the updating progress?
cd .. && tar xf $NEWUPDATE && mv $NEWUPDATE $INSTALLED
fi
# we're always starting from our working directory
cd $KOREADER_DIR
# export load library path for some old firmware
export LD_LIBRARY_PATH=${KOREADER_DIR}/libs:$LD_LIBRARY_PATH
# export trained OCR data directory
export TESSDATA_PREFIX="data"
# export external font directory
export EXT_FONT_DIR="~/fonts"
# set fullscreen mode
export SDL_FULLSCREEN=1
./reader.lua -d ~/Documents

@ -0,0 +1,15 @@
{
"architecture": "armhf",
"description": "An ebook reader application supports PDF, DJVU, EPUB, FB2 and much more, running on Kindle, Kobo, PocketBook, Ubuntu touch and Android devices",
"framework": "ubuntu-sdk-14.10",
"hooks": {
"koreader": {
"apparmor": "koreader.apparmor",
"desktop": "koreader.desktop"
}
},
"maintainer": "Huang Xin <chrox.huang@gmail.com>",
"name": "org.koreader.koreader",
"title": "Koreader for Ubuntu touch",
"version": "0.0.1"
}

@ -0,0 +1 @@
Subproject commit 1d0cd7583c27025a69e340ac77cab3c53cdef8ba

@ -1,8 +1,9 @@
local InputContainer = require("ui/widget/container/inputcontainer")
local LoginDialog = require("ui/widget/logindialog")
local InfoMessage = require("ui/widget/infomessage")
local DocSettings = require("docsettings")
local NetworkMgr = require("ui/networkmgr")
local DataStorage = require("datastorage")
local DocSettings = require("docsettings")
local UIManager = require("ui/uimanager")
local Screen = require("device").screen
local Event = require("ui/event")
@ -18,7 +19,7 @@ local EvernoteExporter = InputContainer:new{
notebook_name = _("Koreader Notes"),
evernote_domain = nil,
notemarks = _("Note: "),
clipping_dir = "./clipboard",
clipping_dir = DataStorage:getDataDir() .. "/clipboard",
evernote_token,
notebook_guid,

@ -12,8 +12,9 @@ local DEBUG = require("dbg")
local T = require("ffi/util").template
local _ = require("gettext")
local tableutil = require("tableutil")
local DataStorage = require("datastorage")
local statistics_dir = "./statistics"
local statistics_dir = DataStorage:getDataDir() .. "/statistics"
local ReaderStatistics = InputContainer:new {
last_time = nil,
@ -382,7 +383,7 @@ end
function ReaderStatistics:importFromFile(item)
item = string.gsub(item, "^%s*(.-)%s*$", "%1") --trim
if lfs.attributes(statistics_dir, "mode") ~= "directory" then
lfs.mkdir("statistics")
lfs.mkdir(statistics_dir)
end
local statisticFile = statistics_dir .. "/" .. item
local ok, stored = pcall(dofile, statisticFile)

Loading…
Cancel
Save