Modern Android companion for Xournal++ (.xopp). Fast handwriting, PDF annotation, graphics tablet & shortcut key support, lossless round-trips, and built-in STEM drafting tools.
Kotlin
0
2 commits
updated Oct 4, 2026
MobiXournal opens, edits, and saves Xournal++ .xopp
files on Android. It is an independent, unofficial project by amarzano2005, not affiliated
with, endorsed by, or maintained by the Xournal++ authors, and it installs under the label
MobiXournal. Draw and handwrite with a pen/stylus on a tablet or phone, then
save back to the same .xopp format so the file round-trips cleanly to and from desktop
Xournal++ on Linux. The guiding principle is format fidelity and round-trip safety: a file
edited on Android reopens correctly on the desktop, and vice versa.
Built with deep, dedicated support for STEM disciplines (Science, Technology, Engineering, and
Mathematics), MobiXournal equips students, educators, and professionals with specialized tools for
technical note-taking: electronic circuits (resistors, capacitors, inductors, ground), digital logic
gates (AND, NAND, OR, NOR, XOR, XNOR, NOT), relational database schema tables, coordinate axes,
parametric splines, regular geometric figures, virtual drafting instruments (setsquare, compass,
protractor), and on-device LaTeX formula rendering β all saved as pure, standard .xopp strokes
that round-trip losslessly to desktop Xournal++.
Based on Xournal++ β credits and licence. This app is a derivative work: its
.xoppformat handling, colour palette, shape recogniser and highlighter behaviour are derived from or matched to Xournal++, whose authors hold the copyright in that work. Xournal++ is licensed under GPL-2.0-or-later, so this app is distributed under the same licence β seeLICENSE. The app icon is this project's own artwork. Source: github.com/amarzano2005/MobiXournal.Based on NeXopp. MobiXournal is a continuation of NeXopp by Brian Monroe (
bamonroe) β the same Android.xoppeditor this codebase started from. The document layer, editor, build tooling and documentation structure come from there, under its GPL-2.0-or-later licence; the project has been renamed, rebranded and extended since. NeXopp's author is credited in the About page andNOTICE.
AGENTS.md..xopp schema, data path, model): docs/architecture.md.docs/tools.md.TODO.toml; what's already shipped: FINISHED.toml. These are TOML task files driven by the todo skill β run scripts/todo.sh list or scripts/todo.sh stats to read them.Status: the
.xoppread/write core and its tests are in place, and the Android editor is functional β pen/highlighter/eraser drawing with pressure, colour and width pickers, undo/redo, zoom, pan, a page navigator (add/remove/jump, 1-4 pages per row), on-device authoring of text/image/LaTeX elements, LaTeX math rendering, multi-page documents with layers and backgrounds, PDF import and export, and a rich STEM suite (electronic circuits, digital logic gates, relational tables, coordinate axes, splines, and virtual drafting guides). The controls live in a vertical rail and a dual top bar. Runscripts/todo.sh listfor what's next.
Everything builds through the shared Android toolchain in /data/android (a baked
android-builder:local container), so the only host requirement is Docker. You do not need
a local JDK, Android SDK, or Gradle. To run the app on a virtual device you additionally need a
KVM-capable host for that directory's headless emulator (see docs/tools.md).
The one command you need:
scripts/build.sh
This runs the full check loop through the shared toolchain container β unit tests + a debug
APK. Task variants, output paths, caching behaviour and the rest of the pipeline live in
docs/tools.md, the authoritative home for the build.
The unit tests run on the JVM with no device attached, covering the .xopp round-trip, the pure
render/ geometry and the audio sidecar mapping. What each one asserts β and the rule for the
optional real-file udiff.xopp test β is documented in
docs/architecture.md.
Installing and launching the built APK β the headless emulator (emulator.sh install /
launch), when a raw adb install to a physical device is appropriate, and how builds reach
the owner's tablets and phones β is documented in docs/tools.md. That is the
authoritative flow; don't invent another one.
MobiXournal is purpose-built for the rigorous demands of STEM education, scientific research, and engineering workflows. Rather than struggling with wobbly freehand sketches or switching between separate apps, you have a complete technical toolbox at your fingertips that produces clean vector figures and round-trips losslessly to desktop Xournal++:
Electrical & Electronic Engineering:
Digital Logic & Computer Engineering:
Computer Science & Relational Databases:
Calculus, Physics & Advanced Mathematics:
Coordinate Geometry, Vectors & Analytics:
Virtual Technical Drafting Instruments:
Engineering Paper & Snapping:
100% Round-trip Safety:
.xopp stroke geometry in the native Xournal++ format, so your technical diagrams reopen identically on Linux, macOS, and Windows.First-launch onboarding β on fresh installations, MobiXournal displays a 3-step introductory guide explaining stylus pressure and barrel button configuration, how to harmonize figure sizes with pen pressure sensitivity, and how to configure shortcuts for graphics tablets and keyboards. You can navigate through it with Next / Back or dismiss it with Skip / Get started.
Open β the top-bar menu (the β° button, top right) has Open; it launches the system
file picker; choose a file. It's read in place via the Storage Access Framework. Open accepts
several kinds of file and works out which is which from the file's contents, not its name: a
gzip-compressed .xopp (the usual desktop format), a single-file zipped .xopp package (its
bundled PDF travels inside), an uncompressed Xournal++ XML file, a plain PDF β picking a
PDF opens it as a fresh annotatable document exactly as Import PDF below does β and a
plain-text file (see Open a text file below), and an image (see Open an image
below). A file that
is none of these is refused with an "Open failed" notice. Whichever .xopp container it came
from is remembered, so a later Save writes it back in the same one.
Files on remote shares work too β anything the system picker lists, including SSHFS, FTP,
WebDAV and cloud providers mounted as storage. Those reads can be slow, so the document is
fetched in the background behind an "Openingβ¦" note and only appears once it has fully landed;
a link that drops mid-transfer leaves the app as it was and reports the failure. Every
page is shown, one above the next, each drawn with its own background ruling (plain, lined,
ruled, graph, or dotted) and all of its layers β including strokes, text boxes, images, and
LaTeX images (rendered as real math β fractions, super/subscripts, roots, and Greek/operator
symbols; malformed formulae fall back to their source text). If the .xopp was made by
annotating a PDF, its PDF background is reloaded automatically β the reference the file
stores is resolved and the PDF pages render underneath your annotations again, so a saved
project reopens intact. Every way Xournal++ can name that PDF is understood: a plain file path,
a path relative to the .xopp itself (bg.pdf or scans/bg.pdf β how a portable,
desktop-authored document usually stores it), and an attached yourfile.xopp.bg.pdf sibling.
If the referenced PDF can't be found (e.g. a desktop path that doesn't exist on the device, or a
folder MobiXournal wasn't given access to), those pages open blank and a notice is shown β the
reference itself is kept, so saving the file doesn't throw the background away.
Open a PDF from another app β MobiXournal registers as a PDF handler, so it shows up in the
Open with / Share sheet of file managers, browsers, and mail clients. Tap a PDF there,
pick Xournal++, and it opens straight into a new tab as a fresh annotatable document over the
PDF's pages β the same result as opening that PDF through the menu's Open. This works whether
the app was closed or already running; a PDF handed over while it's running is added as another
tab, leaving the documents you already had open untouched. The tab is named after the PDF.
The first Save asks where to put the .xopp. A PDF handed over this way has no .xopp file
behind it, and MobiXournal never writes document bytes over your original PDF β so the first Save
opens the destination picker, pre-filled with the PDF's own name and a .xopp extension
(bhm_prior.pdf β bhm_prior.xopp), which normally puts the annotations beside the original.
After that first save the tab belongs to the .xopp it was written to, and later Saves write
straight back to it. The PDF stays on as the page background and is referenced by the saved
file, so the document reopens over those same pages in desktop Xournal++ (Save Asβ¦ β zipped
package embeds the PDF inside the file instead, if you'd rather carry it around as one file).
Open a .xopp from another app β a .xopp is a document type of its own, not a generic
blob: MobiXournal writes every file it saves as application/x-xopp β the same type desktop
Xournal++ declares for .xopp β and registers itself as a handler for it. So a .xopp now shows
up in a file manager's Open with / Share sheet with Xournal++ offered, and tapping it
there opens straight into a new tab, exactly like opening it through the menu's Open. (A
file that arrives over a plain file:// link is matched by extension too, so an Open with
still works even where the system doesn't recognise the type.)
Tabs β several documents open at once β every document you open lives in its own tab, and the tab strip under the top bar is always shown β even with a single document open β so the same tab controls are always in the same place. Tap a tab to switch to that document; every tab carries its own β, so you can close any document without switching to it first; tap + at the end of the strip β or New document in the β° menu β to start a fresh blank document in a new tab. The tabs, the β and the + are all finger-sized targets, so switching or closing a document works with a fingertip and doesn't need a stylus. The strip is kept deliberately compact (a slim 42dp band) so it gives up as little of the canvas as it can. Open always opens into a new tab rather than replacing what you're working on. Each tab carries its own save format, its own background PDF and the page you were on, so switching back lands you where you left off. Closing the last tab leaves you on a fresh blank document. One thing to note: undo history doesn't follow a tab switch β the incoming document starts with a clean undo history, though all of its content and unsaved edits are intact. Reopening the app brings the whole strip straight back, however many tabs it holds: each document is read in the background at the moment you switch to it, so the app starts and stays responsive instead of stalling on a big session.
Split view β two documents side by side β Split view in the β° menu divides the drawing area into a left and a right pane, each showing its own document. Drag the bar down the middle to rebalance the two halves (it's a finger-wide grab strip, and neither pane can be squeezed below about a sixth of the width). Each pane has its own tab strip, so the two halves hold entirely separate sets of open documents, and each keeps its own scroll position, zoom, current page, layers and undo history. Handy for copying between two notebooks, or for writing notes beside a PDF you're reading.
The toolbar and the β° menu always drive the pane you last touched β tap or draw in a pane to give it focus, and Save, Import PDF, the pen settings and undo/redo then apply to that document. Choosing Close split view hands the whole area back to the left pane; the right pane's tabs are kept, so turning split view on again brings the same documents back.
Tab overview β see every open document at a glance β the grid button in the top bar (between redo and the β° menu) opens a grid of every tab in the current pane, each shown as a small picture of the page that tab was left on, with its name underneath and the current tab outlined. Tap a picture to switch straight to that document. It is the quickest way to find the right document when several tabs are named alike (or are all "Untitled"). Pictures appear as they are drawn β a document that hasn't been reopened since the app started has to be read from the session cache first, so its card is blank for a moment. PDF and image page backgrounds aren't drawn in the pictures; your handwriting and drawings are.
The tab strip scrolls sideways β open more documents than fit across the screen and the strip scrolls rather than pushing tabs off the edge, so every tab (and the trailing +) stays reachable. Drag anywhere on the strip except the current tab to scroll it, and the selected tab is always scrolled back into view when you switch documents.
Drag the current tab sideways to reorder it β press the selected tab and slide it left or right along its strip to move it past its neighbours; the order sticks and is restored with the rest of the session. Only the selected tab reorders β dragging any other tab scrolls the strip instead, so tap a tab first if you want to move it. A drag only takes over once your finger has actually moved, so a plain tap still switches document and a stationary hold still opens the long-press menu below. Dragging reorders within a strip; use that menu to send a tab to the other pane.
Long-press a tab to send it to the other view β holding a tab pops up a small menu with two entries. Move to other view takes that document out of this pane and opens it in the other one; Mirror on other view leaves it where it is and opens a second view of the same document in the other pane. Either one opens split view automatically if it was closed.
A mirrored document is live in both panes β the two mirrored tabs are two windows onto one document, not two copies: a stroke, an erase or a page change made on one side appears on the other immediately, and both save back to the same file. The views stay independent in every other respect β each keeps its own scroll position, zoom and current page, so you can work at the top of a page on the left while watching the bottom of it on the right, or keep a diagram in view while writing about it further down. Undo lives in the pane you are editing in: the other view drops its undo history when it takes an edit, so an undo can't quietly discard the work the other side just did.
Because tabs are named after files, and different files are often named alike, mirrored tabs are marked with a small coloured dot. Tabs sharing a dot colour are views of the same document β two "notes.xopp" tabs with no dots are two different files that merely share a name.
Tabs are restored when you reopen the app β the set of open tabs is cached on the device
(including edits you hadn't saved yet), so closing the app and starting it again brings back
exactly the tabs you had, with the same one showing. This is a convenience cache, not a
substitute for saving: your .xopp file on disk is still only written when you Save, and
that file is the only thing desktop Xournal++ ever sees.
Open a text file β picking a plain-text file (a .txt, a log, a source file, notes) opens
it as an annotatable document: the text is typeset onto A4 pages in a monospace face, wrapped
at the margin and split across as many pages as it needs, and those pages become the document you
draw on. The text is real, selectable text, not a picture of text, so the Select text (PDF)
tool works on it and you can copy passages straight out. Annotate it exactly like any other
document. The first Save asks where to put the .xopp, since a text file has no .xopp of
its own, and the typeset pages are saved inside the .xopp (the zipped single-file package) β
so the file reopens with its text intact on this device and in desktop Xournal++, with nothing
else to keep alongside it. Reopening the same text file again reuses the pages already typeset.
A file named .md or .markdown is recognised as markdown and typeset as markdown,
cached separately from the same text opened under a .txt name. Headings are set large and bold,
**bold** and *italic* are drawn in real bold and italic type, `code` and fenced code
blocks in monospace, lists get hanging bullets or numbers, block quotes are indented, and ---
becomes a drawn horizontal rule β with the markup characters themselves gone from the page. The
result is still selectable text, so Select text (PDF) copies the words without the syntax.
Very large files are refused rather than opened: typesetting a huge log takes minutes and fills
the cache, so a file over the text import limit (64 MB by default) comes back as "Text file is
N MB, over the 64 MB import limit" instead of stalling the app. Raise or lower that limit under
Settings β Storage.
Open an image β picking a PNG, JPEG or WebP opens it as a one-page document with the
picture as the page background, at the picture's own proportions, with an empty layer on top to
draw on. Annotate it like any other document. The image itself is linked, not copied β the
saved .xopp points at the picture where it already lives, so keep it in place β and, as with a
PDF, the first Save asks where to put the .xopp, since an image has no .xopp of its own.
A truncated or corrupt image is refused with a "Couldn't read that image" notice.
MobiXournal also registers as an image handler, so β exactly as with a PDF β it appears in the
Open with / Share sheet of gallery apps, file managers, browsers, and mail clients: tap a
picture there, pick Xournal++, and it opens in a new tab without disturbing the tabs you
already had.
Reopening such a .xopp finds its picture again the same ways desktop Xournal++ does: by
content:// URI, by absolute path, by a path relative to the .xopp's own folder, or from
the sibling file an attached background names. A picture that can't be found leaves those pages
blank with a "Background image not found" notice β the reference itself is preserved, so
putting the file back makes it render again. Saving through Save Asβ¦ β zipped .xopp instead
bundles the pictures inside the .xopp, one archive entry per image-backed
page, so the file carries its backgrounds to another machine.
Import PDF β the menu's Import PDF first asks how the PDF should join the document:
Replace (the PDF's pages become the document, discarding the pages currently open) or
Append (the PDF's pages are added after the pages already open, keeping their annotations β
and it's a single undo away). A .xopp can reference just one background PDF, so appending onto a
document that already has one merges the two into a single joined PDF β the incoming PDF's
pages are added to the end of the existing background PDF, that joined file becomes the document's
one background source, and the appended pages are renumbered against it. Repeat appends keep
composing onto the joined PDF without touching the original files, and the joined PDF is what the
saved .xopp links to (or embeds, for a zipped Save As), so the result reopens in desktop
Xournal++ with every appended page's background intact. Appending onto a brand-new, untouched blank page drops that stray blank sheet. Choosing a
mode launches the picker filtered to PDFs; the import gives you one page per PDF page, each PDF
page rasterised and shown as the page background (Γ la desktop Xournal++ PDF annotation). Draw on top as usual; the strokes are
kept separate from the PDF and the pdf backgrounds round-trip when you Save the .xopp.
The source PDF's reference is recorded in the saved file, so reopening the .xopp later
reloads that PDF and shows the same backgrounds again β no need to re-import.
MobiXournal writes that reference as a relative path whenever it can: if the PDF sits in the same
folder you save the .xopp into, the file records just thepdf.pdf rather than a device-specific
location. That's the portable form β copy the two files to a Linux box together and desktop
Xournal++ finds the background exactly as it does here. When the PDF lives somewhere else
entirely, the full reference is recorded instead, which still works on this device. Nothing to
configure; it just picks the more portable of the two.
Select text (PDF) β for an imported PDF that carries a real text layer (i.e. not a pure scan), the rail's Select slot's Select text (PDF) member lets you drag across the page to select the underlying text; the selected words highlight, and a Copy button puts them on the system clipboard to paste elsewhere. It reads the PDF's own text β no OCR β so scanned image-only PDFs have nothing to select (OCR for those is planned). The selection is view-only and doesn't change the document.
Vertical space β pick Vertical space from the rail to reflow a page: drag down on the page to insert blank vertical space, pushing everything below the grab line down with your finger, or drag up to close a gap and pull that content back. A dashed guide shows the grab line while you drag; only objects whose top edge is below the line move (one the line passes through stays put rather than being torn), and all layers move together. The whole drag is a single undo step, and since it only shifts coordinates it round-trips to desktop Xournal++ unchanged.
Draw β the controls live in a vertical rail down the left edge. It starts with the
tool slots, each standing for a tool or a group of related tools and showing the one that group
is currently set to: Pen, Highlighter, Eraser (partial Β· whole stroke), Line, Rectangle, Shapes
(ellipse Β· arrow Β· double arrow Β· coordinate axis Β· spline), Table, Circuits
(resistor Β· capacitor Β· inductor Β· ground), Logic gates (AND Β· OR Β· NOT Β· NAND Β· NOR Β· XOR Β· XNOR gates), Pan, Select (rectangle Β· lasso Β· select text Β· background copy),
Insert (image), Text (text Β· LaTeX), Vertical space, and Play object. Line and Rectangle get a slot of
their own because they are the shapes you reach for most; every other figure shares the Shapes
slot, whose face starts as the ellipse (the circle). Tap a slot to switch to the tool it shows β
the active slot is highlighted; tap it again once it is the live tool to open a picker over the
group's other members (no long-press needed, though a long-press still works), and picking one both
switches to that tool and re-faces the slot. Those per-slot choices are remembered across app
restarts, so the rail comes back the way you left it. The pop-up buttons β Colour & size,
Shape recognition, Guides, Layers, Zoom, Background, Pages, Audio β each open a small
menu anchored to their own button (opening to the right of the rail); tapping the button again
closes it. A tool slot whose menu offers a choice of tools (any group with more than one member)
wears a small chevron (β) in its bottom-right corner, so a slot that can be re-faced reads
differently at a glance from one that just activates a single tool. The pop-up buttons above do
not wear it: they each open their own panel, not a submenu of alternatives. The Play object slot sits at the very bottom of the rail. Pick Pen or Highlighter and draw with
one finger or the stylus; pen pressure sets stroke width. The Highlighter instead lays down a broad,
constant-width band (pressure-independent) that blends like a real marker β a multiply blend at
desktop Xournal++'s ~47% opacity, so dark ink shows through darkened rather than veiled β and
saves as a highlighter stroke (colour alpha 7f, the byte the desktop app writes) that reopens
the same way in desktop Xournal++. Its
thickness is snapped to desktop Xournal++'s own highlighter tips (1 mm / 3 mm / 7 mm), so a
highlighter drawn here is as thick as one drawn there, whatever the pen's width slots are set to.
Choose a colour and a base width
from the Colour & size pop-up, which holds colour, width and line style in one compact
menu β its button face is a
dot sized to the current width and filled with the current colour. The swatches are
eight colours: Black (#000000), Red (#FF0000), Green (#008000), Blue (#3333CC), Orange (#FF8000), Magenta (#FF00FF), Yellow (#FFFF00), White (#FFFFFF), in that order, each hex taken
from desktop Xournal++'s own palette so a
colour picked here is byte-for-byte the colour it would write there β and the palette itself is
yours to change under Settings β Colors (add, redefine, delete). Its colour half ends with an
editable custom slot (marked with a pencil): tap it to draw with its current colour, or long-press it to
open a picker β a saturation/value square over a hue slider plus a #RRGGBB hex field β to set any
colour. Its size half offers three width slots as one compact row of small boxes, each drawn as a filled dot sized to that
slot's width (the widest slot fills the box, the rest scale down in proportion) under its exact
point size, so the three read as a tip-size ladder rather than three arbitrary letters: tap a
slot to draw with it, or long-press a slot to open a resize dialog (0.5 β 15 pt) that redefines
that slot's width β drag the slider for a broad sweep, tap β / + to nudge it 0.1 pt at
a time, or type an exact point size into the text field. That same palette β swatches and the
custom slot β is what the text-box dialog and the selection recolour menu offer, so the three
always agree. The custom colour, the three widths,
and the colour/width you were last drawing with are all remembered across restarts,
so the app reopens with the pen you left off with. Each tool keeps its own colour and width
across a switch: the pen comes back to the pen's, the highlighter and the figures to theirs β and
that holds whichever way you switch (rail slot, keyboard shortcut, barrel button),
so picking the pen after a fat figure or highlighter draws with the pen's own medium width again
instead of inheriting theirs. New strokes land on the active layer
(see Layers below) of whichever page you draw on.
Line & shapes β the rail's Line, Rectangle, Shapes, and Table slots offer Line,
Rectangle, Ellipse, the STEM figures (Triangle, Square, Rhombus, Pentagon,
Hexagon, Star), Table, Coordinate axis, Spline, and the two arrow tools (Arrow, Double arrow);
Line, Rectangle, and Table are one tool each; the rest share the Shapes slot (with the figures first and the
arrows separated by a divider; order and visibility can be customised in Settings β Figures). Pick
one and drag from one corner/endpoint to the other; a live preview follows your finger and the
shape commits on release. The Table tool lets you draw or insert custom grid tables: configure the number
of rows and columns directly on the canvas via the contextual bar (or under Settings β Figures), toggle
Header to add a relational double separator line under the first row (the relational database schema standard),
then drag to size it interactively, or tap Insert to place it centered in the visible viewport. Tables are stroked with
figure styling (adjustable shape width, color, and line style) and round-trip losslessly to desktop Xournal++ as standard strokes.
Shapes are saved as ordinary strokes in the current pen colour and the
shape width β a width of its own, kept separate from the pen's and defaulting to the middle
size slot, the same one the pen starts at (the default slot is set in Settings β Figures), so
a fresh shape and fresh handwriting come out the same weight; the wide slot is left to the
highlighter. A shape draws at that width directly β it does not taper with pen pressure the way a
freehand stroke does, so with pressure on a shape can look thicker than a light pen stroke (the
Figures section is where you compensate); a shape and a fully-pressed pen match. Set the width from
the Colour & size pop-up while a line/shape tool is active (tap a width slot, or long-press one
to redefine it); that same pop-up carries the Line style submenu β Solid, Dashed,
Dash-dot, Dotted β so the pen and the figures can be dashed without leaving it. Width and
style are remembered across restarts. The result round-trips to desktop Xournal++ like any other stroke. A double arrow gets a head at each
end; a coordinate axis puts its origin where the drag started and runs an arrowed x and y axis out
to the drag's width and height. The Spline tool is for a smooth curve through points you place one
at a time. Tap to drop a control point; drag away from a tap instead of lifting to pull out
a tangent handle that bows the curve through that point (lift where you want the curve to lean).
Keep tapping to extend it β the whole curve previews live as you go, with a dot on every control
point, a line through each tangent handle showing how hard that point is bowed, and a dashed
rubber band from the last point to a hovering stylus, so you can see where the next tap will take
it. While a curve is open, a bar shows how many points it has and offers Finish (disabled
until there are two, since a single point draws nothing), an undo button that drops just the
last point, and a close button that discards the whole curve. Double-tap or Enter also
finishes it, Backspace drops the last point, and Escape or Back throws it away;
switching to another tool commits whatever you have so far. The result is one ordinary constant-width stroke in
the current pen colour and width, so it round-trips to desktop Xournal++ like any other stroke.
The Colour & size pop-up sets Line style (Solid, Dashed,
Dash-dot, Dotted) as a row of chips, as well as the
colour and the tip size β there is no separate Style slot any more, so the three are one tap
from the rail. The line style
applies to all shapes and strokes drawn with the line/shape tools and saves on the <stroke>
element (style), reopening the same way in desktop Xournal++. Fill is gone: the app no
longer offers it, and strokes drawn here are never flooded β a .xopp that already carries
fill on a stroke still opens, renders and re-saves with it untouched.
Electronic circuits β the rail's (and secondary top bar's) Circuits tool offers fundamental passive circuit components: Resistor (standard 6-peak zigzag between lead wires), Capacitor (parallel plates with symmetric terminal wires), Inductor (smooth 4-loop coil), and Ground (3-tier stepped earth/chassis ground symbol). Drag from the start terminal to the end terminal; the component dynamically scales and rotates along your drag vector with clean engineering proportions. Drawn in the active shape width and pen colour, circuits save as standard constant-width strokes that round-trip losslessly to desktop Xournal++.
Logic gates β the Logic gates tool provides the complete IEEE-standard digital logic gate set for computer science, digital logic design, and boolean algebra: AND, NAND (with inversion bubble), OR, NOR, XOR (with dual curved input arcs), XNOR (dual curved input arcs plus output inversion bubble), and NOT (inverter triangle + bubble). Drag from the input side toward the output; the gate is drawn with symmetrical input leads and an output wire, oriented precisely along your drag vector. Like all figures, logic gates round-trip cleanly to desktop Xournal++ as standard strokes.
Shape recognition β turn it on from the rail's Shape recognition button (the triangle; it tints while on, and the state is the same persisted setting as Settings β Stylus β Shape recognition, so you can flip it mid-page without leaving the editor) and a freehand stroke is snapped, the moment you lift, to the shape it clearly resembles: a straight line, a triangle, a rectangle, or a circle. This is desktop Xournal++'s own shape recognizer, ported line for line with its thresholds intact, so a stroke is judged here exactly the way it is judged on the desktop β and, as there, that means circles rather than ovals: an ellipse stroke is left as drawn. Anything else the recogniser doesn't recognise β handwriting above all, but also arrows and open polylines, which upstream doesn't attempt β is kept exactly as you drew it, and a stroke under 40 pt across is never snapped at all. A rectangle you draw roughly upright is squared to the page axes, and the corners of every recognised shape are rebuilt from where the fitted lines cross, so they come out sharp instead of wobbly. The result is one ordinary constant-width stroke, so it round-trips to desktop Xournal++ like any other. The toggle is on by default and applies to the pen and the highlighter alike β as on desktop, where both tools carry the recogniser β so a straight highlighter line snaps to a line too.
Snapping β two optional aids under Settings β Editor. Snap to grid pulls the start and end of a shape drag onto the page background's ruling, so lines and boxes line up with the paper: a graph or dotted page snaps both axes to its squares, a lined/ruled page snaps only the vertical position (it rules no vertical lines), and a plain page snaps nothing. Snap rotation makes the selection's rotate handle step in 15Β° increments β handy for turning something exactly upright or square. Both are off by default, and neither changes what is written to the file: the result is still ordinary stroke geometry.
Drawing guides (setsquare, compass & protractor) β the Guides rail button lays a virtual instrument on
the page: a Setsquare (a 30/60/90 geometry triangle), a Compass (a circle), or a Protractor (a graduated semicircular scale with 5Β°/15Β° ticks and degree labels). Anything drawn near the protractor's flat diameter rules straight, near its curved rim snaps to a circular arc, and vectors drawn through its body snap to 15Β° radial angles. Anything you
draw within about a quarter-inch of the instrument's edge is ruled onto it, so a freehand stroke
along the setsquare comes out perfectly straight and a stroke swept around the compass comes out as
a clean arc of that radius; move the pen away from the edge and it draws freehand again. Slide the
guide with a finger placed on its body β inside the setsquare's shaded triangle, or on the
compass's centre dot β and drag its amber tip handle to re-pose it: that rotates and resizes the
setsquare (with Snap rotation on it lands on 15Β° steps) and opens or closes the compass. The
edges themselves are left free to draw against, so ruling along the outside of the setsquare never
drags it out from under your pen, and you can go on holding it steady while you draw. Choose
Off to take it away. The guide is purely an input aid: it is never written to the .xopp file,
so what you draw with it is ordinary stroke geometry. Which guide is out is remembered across
app restarts.
Erase β tap the rail's Eraser slot and drag over strokes. Long-press the slot to pick
which eraser it stands for: Eraser (partial) rubs out just the part of a stroke the eraser
passes over, splitting it into the surviving pieces; Eraser (whole stroke) removes any stroke
the eraser touches entirely. Like every tool slot, the choice is remembered across restarts. The
eraser has no size of its own β its tip follows the width slots in the Colour & size pop-up:
the tip's radius is the selected pen's
full width, so the rubber is twice as wide as the ink it removes β wide enough to bite, narrow
enough to erase precisely β and the three slots still give three clearly different tips. It is
measured in document points, so it rubs out the same amount of ink whatever the zoom. A thin black
circle shows exactly where the tip's edge falls β it follows a hovering stylus, and follows the
contact point while you rub (finger touches included). When you erase by holding the stylus
barrel button, the circle appears the moment the button goes down, so you can see the tip's reach
before touching the page. It is on-screen chrome only: it is never part of the page and never
written to the .xopp file. The eraser only affects the
selected layer β ink on other layers is left alone β and hidden layers are never erased. If your stylus has an eraser tip (the flip-over
end), using it erases no matter which tool is selected; so does holding the stylus barrel button
(configurable β see Settings) β and the tip circle appears the moment the button goes down while
the pen hovers, so you can see what you are about to rub out before touching the glass. The button
is understood however your pen reports it: the standard stylus button bits, the
barrel-button key events a Bluetooth pen sends on Android 14 and later, or a plain right-click
from a pen the tablet only ever sees as a mouse (which is how some tablets present a pen they never
promoted to a stylus). Pressing it mid-stroke hands the rest of that stroke to the eraser β the
ink already drawn stays, and everything the pen passes over from then on is rubbed out β so holding
the button erases whether you press it before the tip lands or while writing; letting go does not
bring the stroke back. Double-clicking the barrel button with the pen lifted off the
glass runs its own action β undo by default (see Settings).
Layers β the Layers pop-up manages the visible page's layers (top of the list = top of the
page). Each row can make the layer active (tap its name β new ink lands there, marked with a
filled dot), show/hide it in the editor (the eye toggle β hiding is view-only and never changes
the file), reorder it up/down (z-order), merge it down into the layer below (the merge
button β the two layers' contents combine in z-order, the lower layer keeps its name, and the
emptied upper layer goes away; disabled on the bottom layer), rename it, or delete it (a
page always keeps at least one layer). Add layer puts a fresh empty layer on top. With something selected, each row
also shows a move-selection-here button. Layer names round-trip via the <layer name> attribute;
every structural change is undoable.
Stylus β the app is stylus-first. Rest your palm on the screen while you write: once the pen is down, finger/palm touches are ignored for drawing (a second finger still pans). A hovering stylus shows a preview ring where the tip will land. Pen pressure sets stroke width, with a configurable feel, tapering more deeply at a light touch to match desktop Xournal++. Handwriting is smoothed as you write β digitiser wobble in both position and pressure is filtered out, and redundant points are dropped when the pen lifts, so strokes look clean and files stay small. All of this is tuned in Settings below.
Select β the rail's Select slot selects objects the way desktop Xournal++ does. The marquee shape is the tool itself: long-press the slot to pick Select rectangle (drag a box; every object fully inside is selected), Select lasso (trace a free-form loop; everything wholly inside is selected), Select text (PDF), or Select background (flatten). Both shapes allow a few points of slack at the edge, so tracing tightly around a hairline stroke still catches it. A marquee only picks objects on the active layer, as on the desktop β switch layers to select the ink on another one. Or tap a single object to select just that one. Selected objects get a dashed outline with handles:
.xopp format, so they can't be rotated).Object selection edits are undoable, and so is a background Cut. A background Copy only fills the clipboard; the later paste is undoable. (Selection is per page; two-finger pan still works.)
Text β pick Text from the rail's Text slot and tap where you want a text box; a dialog
takes the content from the keyboard and lets you style it: font family (Sans / Serif /
Monospace), bold, italic, a size slider (6β96 pt), and a colour β the same picker
the pen uses, so the custom slot is shared with it. Tapping
an existing text box reopens it for editing with all of that prefilled from the box (clearing the
text deletes it). Every property round-trips to and from desktop Xournal++ via the .xopp
<text> element. (Underline isn't offered β the format can't store it.)
Image β pick Image and tap where the image should go; the system picker opens, and the chosen picture is placed at that point (scaled to a sensible size).
LaTeX β pick LaTeX (the Text slot's second member) and tap to place a math image; a dedicated formula dialog opens with a STEM symbol palette (Calculus, Greek letters, Operators, and Physics shortcuts) for quick insertion at the cursor, and it's rendered as real math.
Undo / Redo β the arrows in the top bar undo and redo edits, one gesture at a time (drawing, erasing, and adding/editing text/image/LaTeX are all undoable). They enable and disable as history allows; opening a file starts fresh history. History is 200 edits deep β past that the oldest step is dropped, so the most recent edits always stay undoable without the stack growing forever.
Scroll β drag with two fingers to move around the page stack, or pick the Hand tool from the rail to pan with one finger (handy on a stylus). A quick one-finger flick keeps the pages gliding with momentum and coasts to a stop β the faster the flick, the much farther it carries β while a two-finger pan stops the instant you lift. Touch down again to halt a glide at once. With the Hand tool, a double-tap navigates: tap twice on the left edge to jump to the previous page, on the right edge for the next page, or in the centre to toggle full-page view (hides the top bar and side toolbar for a distraction-free canvas; double-tap the centre again to restore them). A PDF-style scroll thumb rides the right edge whenever the document is taller than the screen: drag it to page quickly through a long document (a page-number bubble shows where you are as you drag). A small grip bulges out of its centre so it's easy to grab. It sits faint while idle and brightens as you scroll; only the thumb itself grabs touches, so the rest of the page's right margin still takes ink. A page counter ("3 / 12") sits permanently in a corner of the canvas β the bottom-right by default, and movable from Settings βΈ Appearance β so you always know which page of how many you're on; it stays put in full-page view, where the bars are hidden. Directly above it a zoom badge ("125%") in the same pill shows the current zoom level at a glance, and tapping it resets the zoom to 100%. With a mouse connected, the scroll wheel scrolls the document vertically β wheel down moves further down the pages, the same direction as dragging the scroll thumb down β and leaves the zoom level alone.
Back button β the Android back button (or back gesture) navigates instead of quitting. Each press steps one layer out of wherever you are, and only the last press leaves the app. Dialogs and pop-up menus close on back as you'd expect; beyond those, back cancels an unfinished spline, then leaves a text edit or drops a selection, then clears picked pages and leaves the page-overview edit mode, then restores the chrome from full-page view β and finally exits. In Settings, back returns from a section to the settings index, exactly like the on-screen back arrow, and a second press closes Settings back to your document. Back is ignored while a document is opening or saving, so a slow transfer can't be interrupted half-way.
Zoom β pinch with two fingers anywhere on the canvas to zoom in or out; the point between your fingers stays put as the page grows or shrinks, and you can pan at the same time in the one gesture. The % button on the rail also opens a zoom pop-up with β / + buttons; tap the percentage to reset to 100% β or tap the zoom badge above the page counter for the same shortcut without opening anything. Zooming wider than the screen lets you pan sideways. Zoom ranges from 25% to 1000%, so you can work on fine detail; ink stays sharp at every level. PDF page backgrounds stay sharp too: past a certain zoom only the part of the page you can actually see is re-rendered, at full screen resolution, so PDF text is crisp all the way to 1000%. A freshly zoomed or panned area may look soft for a moment before the sharp version lands.
Background β the grid button on the rail opens the page-background pop-up, which sets the
paper ruling of the page in view: Plain (bare sheet), Lined, Ruled (lined with a red
margin), Graph, or Dotted. The current style is check-marked; picking another re-rules the
page immediately (an undoable edit) and round-trips via the <background style> attribute. The
ruling is drawn in desktop Xournal++'s own paper colours β lined rules in its xopp_dodgerblue,
graph/dotted in its xopp_silver β so the paper looks the same on both. On a
PDF or image-backed page there's no solid sheet to re-rule, so the items are disabled.
Pages β the document button on the rail opens the page navigator: it shows Page N / M with β / βΆ to jump to the previous/next page, plus Add page (a blank page after the one in view β it is born at the default page size and keeps the current page's paper ruling, but a PDF/image background is dropped to a plain white sheet so the new page is genuinely blank, not a copy of the page underneath) and Remove page (the one in view; the last page is never removed). Add and remove are undoable.
.xopp, so it round-trips to desktop Xournal++. The pen is
never a candidate for the lift, so drawing on a grid page is unaffected; sliding your finger
before the press registers pans as usual..xopp. The selection is view-only state: it clears when
you return to 1 page per row, and after any page add/remove/reorder (the indices have moved).<page width= height=> attributes to desktop
Xournal++.Settings β the top-bar menu opens Settings, a list of sections β Stylus, Editor, Toolbar, Figures, Colors, Shortcuts, Navigation, Appearance, Storage, Backup and About. Tap a section to open it as its own page; back returns to the list, and back from the list returns to the editor. Your choices persist across restarts. Under Stylus:
755 while no
motion event of the stroke mentions a button at all β and because the button then exists only on
the key stream, a press stays latched until the key comes up rather than being cleared by the
first touch. Holding it applies while you draw as well as before: pressing it mid-stroke
turns the rest of that stroke into an erase. If holding your pen's button still does nothing,
open β° menu β Pen diagnostics (below) and press the button over the canvas: if nothing at all
appears, the tablet is swallowing the button before any app sees it β on some Honor/Huawei styli
the side button is wired into the vendor's own apps only, and no setting in this app can reach
it. That is also the pen whose press exists only as a click (its firmware reports one press for
a whole double-click, and nothing at all for a single tap), so the Barrel button choice above
is inert on it and Barrel double-click below is the setting that matters. Such pens still have
their own paths: the flipped-over eraser end, and the keyboard shortcuts set under Shortcuts
below. If the log shows a key you do not expect, send it on β that is a path the app can learn.stylus/mouse/finger), button bits, key codes and source flags. It is the
way to find out what a stylus really sends, and it stays on the canvas because that is the only
place the pen's events arrive: press and hold the side button while drawing and read the last few
lines. The log also carries lines the app itself adds β CLICK -> toggle eraser, or CLICK swallowed (same gesture) β which say what it did with the press, next to what arrived, so a dead
button can be traced to the pen, to the tablet, or to the app's own reading of the event.
Copy puts the whole log on the clipboard if you want to send it on, and Clear
empties it without closing the panel; back or the menu closes it. It is a debugging aid, not a
preference β it starts off every launch and nothing about drawing changes while it is on..xopp. Lowering it keeps
files small. Existing strokes are unaffected β the setting applies to what you draw next.
The budget is also capped in page units, so a stroke drawn zoomed out or in the multi-page
overview stores the same detail as one drawn at 100% β zooming out never costs you precision.Under Shortcuts β the keyboard shortcuts, gathered in their own section rather than mixed in with the input behaviours:
Optimizing for graphics tablets (tavoletta grafica): MobiXournal works seamlessly with external USB (via OTG) and Bluetooth drawing tablets (such as Wacom, Huion, XP-Pen, and Gaomon). Recommended setup:
S or M) to balance them with your average pen pressure, or disable pressure sensitivity in Settings β Stylus for completely uniform strokes across pen and figures.Under Editor:
Under Toolbar:
Under Figures:
Under Colors:
Black (#000000)), with an edit button opening the HSV/hex picker and a delete button
removing it. Add colour appends a new swatch (the grid is capped so it stays a grid), and
Restore default palette puts back the eight defaults. The last remaining colour cannot be
deleted β an empty palette would leave the pickers with nothing to pick β and deleting a colour also
drops its keyboard shortcut, so no key points at a swatch that no longer exists.Under Navigation:
Under Appearance:
Under Storage β two budgets that bound what opening documents costs on disk and in memory:
Under Backup β export and import preferences across devices and versions:
.json backup file via the system file picker.Under About β what this build is and where it came from:
LICENSE, and the page links to the GPL and to the
Xournal++ project..xopp editor
this codebase continues, plus a plain statement that this app is unofficial and not affiliated
with the Xournal++ authors.Export PDF β the menu's Export PDF flattens the whole document to a PDF: each page is
drawn at its true size with its background (a PDF page, an image, or a ruled sheet) and every
stroke and element merged on top, then written to the location you pick β pre-filled with the
open document's own name and a .pdf extension, so notes.xopp exports as notes.pdf and
the export lands beside the document it came from (a document that has no name of its own yet is
offered as Untitled.pdf). Pages backed by an
image keep that picture in the export, at print-usable resolution. When a page came from an imported
PDF, its original page is kept as vector content and your annotations are laid over it as
vectors too β so re-exporting an unchanged PDF stays about its original size and sharpness instead
of ballooning from a rasterised copy. Use this to share an annotated copy; Save keeps the
editable .xopp.
Fonts in generated PDFs β when MobiXournal generates a PDF page for you (the text-import path), it
typesets with DejaVu Sans (plus its bold, oblique and bold-oblique companions, used
for markdown emphasis) and DejaVu Sans Mono, which ship inside the app. Because they are
embedded (and subsetted) into the PDF, imported text in Cyrillic, Greek, CJK, or box-drawing
characters renders the same on any viewer without those fonts installed, and the file only carries
the glyphs it actually used. A character even DejaVu doesn't have is drawn as a οΏ½ placeholder
rather than failing the export. Both fonts are freely licensed; the full licence ships with the app
and is checked in at app/src/main/assets/fonts/LICENSE.txt.
Audio (record & replay) β the rail's Audio slot records the microphone while you write,
and every stroke you draw is tagged with the moment in that recording it was started. Tap
Record to start (Android asks for microphone permission the first time), and Stop
recording to finish. Then pick the Play object tool from the rail and tap any stroke to
hear the audio from the instant that stroke was drawn β the same fn/ts stroke tagging desktop
Xournal++ uses, so recordings made there replay here and vice versa. Stop playback in the same
pop-up silences it.
Audio is not stored inside the .xopp β it lives in a .wav file beside it, exactly as on
the desktop. Android only grants an app access to the one file you picked, not its folder, so the
first time you record, use Choose audio folder⦠in the Audio pop-up and pick the folder your
.xopp files live in. MobiXournal then writes new recordings there when you save, and loads a document's
recordings from there when you open it. Until you choose a folder, recording and playback still
work for the session, but the .wav never leaves the app β so a file you take back to the desktop
won't have its audio.
Save β the menu's Save writes the whole document back out to a .xopp file, preserving
every page, layer, background, and element β strokes plus the text, images, and LaTeX images you
authored on-device. Save writes in whichever format you last chose in Save As⦠(see below):
it starts as Original, and once you Save As Zipped, every later Save stays Zipped until
you switch back. Opening a file adopts the format it was stored in.
Save writes straight back to the file the tab came from β no picker β whether that file is
on local storage or a mounted remote share; you're only asked for a location when the tab has no
file yet (or the grant on it has lapsed). The document is encoded locally and then pushed across
in one pass behind a "Savingβ¦" note, so a slow or broken link can never leave a half-written
.xopp on the far end.
Save Asβ¦ β the menu's Save Asβ¦ opens a dialog to name the file and pick its format.
Whatever you type is saved as a .xopp: the name you enter is given the .xopp extension
(and an existing extension is replaced), so a Xournal++ document never lands on disk under a
name β or a type β the system and desktop Xournal++ can't recognise as one:
.xopp (gzip-compressed XML). For a PDF-backed
document the PDF stays linked by location (its path/URI), so the .xopp is small and
reopening it reloads that PDF from where it lives β the interchange-safe default..xopp with the PDF embedded inside it, so
the document is fully portable and moves as a single file. It reopens with its background intact
in MobiXournal itself (the PDF travels in the same file) as well as on desktop Xournal++.
The file on disk is the only source of truth β there's no cloud, account, or custom format.
Every package and what it holds is documented, file by file, in
docs/architecture.md β the authoritative layout. The app's Kotlin
sources live under app/src/main/java/com/mobixournal/ (format/, io/, render/, audio/,
tabs/, panes/, ui/, plus MainActivity.kt), with JVM unit tests under app/src/test/ and
the containerized build in Dockerfile, compose.yaml and scripts/build.sh.
MobiXournal is free software under the GNU General Public License, version 2 or
later β the same licence as Xournal++, the project it is
based on. This is an unofficial derivative: not affiliated with, endorsed by, or maintained by
the Xournal++ authors. The app icon is this project's own artwork. The full text is in
LICENSE. It comes with no warranty.
Kotlin
98.3%
Python
1.4%
Modern Android companion for Xournal++ (.xopp). Fast handwriting, PDF annotation, graphics tablet & shortcut key support, lossless round-trips, and built-in STEM drafting tools.
Kotlin
0
2 commits
updated Oct 4, 2026
MobiXournal opens, edits, and saves Xournal++ .xopp
files on Android. It is an independent, unofficial project by amarzano2005, not affiliated
with, endorsed by, or maintained by the Xournal++ authors, and it installs under the label
MobiXournal. Draw and handwrite with a pen/stylus on a tablet or phone, then
save back to the same .xopp format so the file round-trips cleanly to and from desktop
Xournal++ on Linux. The guiding principle is format fidelity and round-trip safety: a file
edited on Android reopens correctly on the desktop, and vice versa.
Built with deep, dedicated support for STEM disciplines (Science, Technology, Engineering, and
Mathematics), MobiXournal equips students, educators, and professionals with specialized tools for
technical note-taking: electronic circuits (resistors, capacitors, inductors, ground), digital logic
gates (AND, NAND, OR, NOR, XOR, XNOR, NOT), relational database schema tables, coordinate axes,
parametric splines, regular geometric figures, virtual drafting instruments (setsquare, compass,
protractor), and on-device LaTeX formula rendering β all saved as pure, standard .xopp strokes
that round-trip losslessly to desktop Xournal++.
Based on Xournal++ β credits and licence. This app is a derivative work: its
.xoppformat handling, colour palette, shape recogniser and highlighter behaviour are derived from or matched to Xournal++, whose authors hold the copyright in that work. Xournal++ is licensed under GPL-2.0-or-later, so this app is distributed under the same licence β seeLICENSE. The app icon is this project's own artwork. Source: github.com/amarzano2005/MobiXournal.Based on NeXopp. MobiXournal is a continuation of NeXopp by Brian Monroe (
bamonroe) β the same Android.xoppeditor this codebase started from. The document layer, editor, build tooling and documentation structure come from there, under its GPL-2.0-or-later licence; the project has been renamed, rebranded and extended since. NeXopp's author is credited in the About page andNOTICE.
AGENTS.md..xopp schema, data path, model): docs/architecture.md.docs/tools.md.TODO.toml; what's already shipped: FINISHED.toml. These are TOML task files driven by the todo skill β run scripts/todo.sh list or scripts/todo.sh stats to read them.Status: the
.xoppread/write core and its tests are in place, and the Android editor is functional β pen/highlighter/eraser drawing with pressure, colour and width pickers, undo/redo, zoom, pan, a page navigator (add/remove/jump, 1-4 pages per row), on-device authoring of text/image/LaTeX elements, LaTeX math rendering, multi-page documents with layers and backgrounds, PDF import and export, and a rich STEM suite (electronic circuits, digital logic gates, relational tables, coordinate axes, splines, and virtual drafting guides). The controls live in a vertical rail and a dual top bar. Runscripts/todo.sh listfor what's next.
Everything builds through the shared Android toolchain in /data/android (a baked
android-builder:local container), so the only host requirement is Docker. You do not need
a local JDK, Android SDK, or Gradle. To run the app on a virtual device you additionally need a
KVM-capable host for that directory's headless emulator (see docs/tools.md).
The one command you need:
scripts/build.sh
This runs the full check loop through the shared toolchain container β unit tests + a debug
APK. Task variants, output paths, caching behaviour and the rest of the pipeline live in
docs/tools.md, the authoritative home for the build.
The unit tests run on the JVM with no device attached, covering the .xopp round-trip, the pure
render/ geometry and the audio sidecar mapping. What each one asserts β and the rule for the
optional real-file udiff.xopp test β is documented in
docs/architecture.md.
Installing and launching the built APK β the headless emulator (emulator.sh install /
launch), when a raw adb install to a physical device is appropriate, and how builds reach
the owner's tablets and phones β is documented in docs/tools.md. That is the
authoritative flow; don't invent another one.
MobiXournal is purpose-built for the rigorous demands of STEM education, scientific research, and engineering workflows. Rather than struggling with wobbly freehand sketches or switching between separate apps, you have a complete technical toolbox at your fingertips that produces clean vector figures and round-trips losslessly to desktop Xournal++:
Electrical & Electronic Engineering:
Digital Logic & Computer Engineering:
Computer Science & Relational Databases:
Calculus, Physics & Advanced Mathematics:
Coordinate Geometry, Vectors & Analytics:
Virtual Technical Drafting Instruments:
Engineering Paper & Snapping:
100% Round-trip Safety:
.xopp stroke geometry in the native Xournal++ format, so your technical diagrams reopen identically on Linux, macOS, and Windows.First-launch onboarding β on fresh installations, MobiXournal displays a 3-step introductory guide explaining stylus pressure and barrel button configuration, how to harmonize figure sizes with pen pressure sensitivity, and how to configure shortcuts for graphics tablets and keyboards. You can navigate through it with Next / Back or dismiss it with Skip / Get started.
Open β the top-bar menu (the β° button, top right) has Open; it launches the system
file picker; choose a file. It's read in place via the Storage Access Framework. Open accepts
several kinds of file and works out which is which from the file's contents, not its name: a
gzip-compressed .xopp (the usual desktop format), a single-file zipped .xopp package (its
bundled PDF travels inside), an uncompressed Xournal++ XML file, a plain PDF β picking a
PDF opens it as a fresh annotatable document exactly as Import PDF below does β and a
plain-text file (see Open a text file below), and an image (see Open an image
below). A file that
is none of these is refused with an "Open failed" notice. Whichever .xopp container it came
from is remembered, so a later Save writes it back in the same one.
Files on remote shares work too β anything the system picker lists, including SSHFS, FTP,
WebDAV and cloud providers mounted as storage. Those reads can be slow, so the document is
fetched in the background behind an "Openingβ¦" note and only appears once it has fully landed;
a link that drops mid-transfer leaves the app as it was and reports the failure. Every
page is shown, one above the next, each drawn with its own background ruling (plain, lined,
ruled, graph, or dotted) and all of its layers β including strokes, text boxes, images, and
LaTeX images (rendered as real math β fractions, super/subscripts, roots, and Greek/operator
symbols; malformed formulae fall back to their source text). If the .xopp was made by
annotating a PDF, its PDF background is reloaded automatically β the reference the file
stores is resolved and the PDF pages render underneath your annotations again, so a saved
project reopens intact. Every way Xournal++ can name that PDF is understood: a plain file path,
a path relative to the .xopp itself (bg.pdf or scans/bg.pdf β how a portable,
desktop-authored document usually stores it), and an attached yourfile.xopp.bg.pdf sibling.
If the referenced PDF can't be found (e.g. a desktop path that doesn't exist on the device, or a
folder MobiXournal wasn't given access to), those pages open blank and a notice is shown β the
reference itself is kept, so saving the file doesn't throw the background away.
Open a PDF from another app β MobiXournal registers as a PDF handler, so it shows up in the
Open with / Share sheet of file managers, browsers, and mail clients. Tap a PDF there,
pick Xournal++, and it opens straight into a new tab as a fresh annotatable document over the
PDF's pages β the same result as opening that PDF through the menu's Open. This works whether
the app was closed or already running; a PDF handed over while it's running is added as another
tab, leaving the documents you already had open untouched. The tab is named after the PDF.
The first Save asks where to put the .xopp. A PDF handed over this way has no .xopp file
behind it, and MobiXournal never writes document bytes over your original PDF β so the first Save
opens the destination picker, pre-filled with the PDF's own name and a .xopp extension
(bhm_prior.pdf β bhm_prior.xopp), which normally puts the annotations beside the original.
After that first save the tab belongs to the .xopp it was written to, and later Saves write
straight back to it. The PDF stays on as the page background and is referenced by the saved
file, so the document reopens over those same pages in desktop Xournal++ (Save Asβ¦ β zipped
package embeds the PDF inside the file instead, if you'd rather carry it around as one file).
Open a .xopp from another app β a .xopp is a document type of its own, not a generic
blob: MobiXournal writes every file it saves as application/x-xopp β the same type desktop
Xournal++ declares for .xopp β and registers itself as a handler for it. So a .xopp now shows
up in a file manager's Open with / Share sheet with Xournal++ offered, and tapping it
there opens straight into a new tab, exactly like opening it through the menu's Open. (A
file that arrives over a plain file:// link is matched by extension too, so an Open with
still works even where the system doesn't recognise the type.)
Tabs β several documents open at once β every document you open lives in its own tab, and the tab strip under the top bar is always shown β even with a single document open β so the same tab controls are always in the same place. Tap a tab to switch to that document; every tab carries its own β, so you can close any document without switching to it first; tap + at the end of the strip β or New document in the β° menu β to start a fresh blank document in a new tab. The tabs, the β and the + are all finger-sized targets, so switching or closing a document works with a fingertip and doesn't need a stylus. The strip is kept deliberately compact (a slim 42dp band) so it gives up as little of the canvas as it can. Open always opens into a new tab rather than replacing what you're working on. Each tab carries its own save format, its own background PDF and the page you were on, so switching back lands you where you left off. Closing the last tab leaves you on a fresh blank document. One thing to note: undo history doesn't follow a tab switch β the incoming document starts with a clean undo history, though all of its content and unsaved edits are intact. Reopening the app brings the whole strip straight back, however many tabs it holds: each document is read in the background at the moment you switch to it, so the app starts and stays responsive instead of stalling on a big session.
Split view β two documents side by side β Split view in the β° menu divides the drawing area into a left and a right pane, each showing its own document. Drag the bar down the middle to rebalance the two halves (it's a finger-wide grab strip, and neither pane can be squeezed below about a sixth of the width). Each pane has its own tab strip, so the two halves hold entirely separate sets of open documents, and each keeps its own scroll position, zoom, current page, layers and undo history. Handy for copying between two notebooks, or for writing notes beside a PDF you're reading.
The toolbar and the β° menu always drive the pane you last touched β tap or draw in a pane to give it focus, and Save, Import PDF, the pen settings and undo/redo then apply to that document. Choosing Close split view hands the whole area back to the left pane; the right pane's tabs are kept, so turning split view on again brings the same documents back.
Tab overview β see every open document at a glance β the grid button in the top bar (between redo and the β° menu) opens a grid of every tab in the current pane, each shown as a small picture of the page that tab was left on, with its name underneath and the current tab outlined. Tap a picture to switch straight to that document. It is the quickest way to find the right document when several tabs are named alike (or are all "Untitled"). Pictures appear as they are drawn β a document that hasn't been reopened since the app started has to be read from the session cache first, so its card is blank for a moment. PDF and image page backgrounds aren't drawn in the pictures; your handwriting and drawings are.
The tab strip scrolls sideways β open more documents than fit across the screen and the strip scrolls rather than pushing tabs off the edge, so every tab (and the trailing +) stays reachable. Drag anywhere on the strip except the current tab to scroll it, and the selected tab is always scrolled back into view when you switch documents.
Drag the current tab sideways to reorder it β press the selected tab and slide it left or right along its strip to move it past its neighbours; the order sticks and is restored with the rest of the session. Only the selected tab reorders β dragging any other tab scrolls the strip instead, so tap a tab first if you want to move it. A drag only takes over once your finger has actually moved, so a plain tap still switches document and a stationary hold still opens the long-press menu below. Dragging reorders within a strip; use that menu to send a tab to the other pane.
Long-press a tab to send it to the other view β holding a tab pops up a small menu with two entries. Move to other view takes that document out of this pane and opens it in the other one; Mirror on other view leaves it where it is and opens a second view of the same document in the other pane. Either one opens split view automatically if it was closed.
A mirrored document is live in both panes β the two mirrored tabs are two windows onto one document, not two copies: a stroke, an erase or a page change made on one side appears on the other immediately, and both save back to the same file. The views stay independent in every other respect β each keeps its own scroll position, zoom and current page, so you can work at the top of a page on the left while watching the bottom of it on the right, or keep a diagram in view while writing about it further down. Undo lives in the pane you are editing in: the other view drops its undo history when it takes an edit, so an undo can't quietly discard the work the other side just did.
Because tabs are named after files, and different files are often named alike, mirrored tabs are marked with a small coloured dot. Tabs sharing a dot colour are views of the same document β two "notes.xopp" tabs with no dots are two different files that merely share a name.
Tabs are restored when you reopen the app β the set of open tabs is cached on the device
(including edits you hadn't saved yet), so closing the app and starting it again brings back
exactly the tabs you had, with the same one showing. This is a convenience cache, not a
substitute for saving: your .xopp file on disk is still only written when you Save, and
that file is the only thing desktop Xournal++ ever sees.
Open a text file β picking a plain-text file (a .txt, a log, a source file, notes) opens
it as an annotatable document: the text is typeset onto A4 pages in a monospace face, wrapped
at the margin and split across as many pages as it needs, and those pages become the document you
draw on. The text is real, selectable text, not a picture of text, so the Select text (PDF)
tool works on it and you can copy passages straight out. Annotate it exactly like any other
document. The first Save asks where to put the .xopp, since a text file has no .xopp of
its own, and the typeset pages are saved inside the .xopp (the zipped single-file package) β
so the file reopens with its text intact on this device and in desktop Xournal++, with nothing
else to keep alongside it. Reopening the same text file again reuses the pages already typeset.
A file named .md or .markdown is recognised as markdown and typeset as markdown,
cached separately from the same text opened under a .txt name. Headings are set large and bold,
**bold** and *italic* are drawn in real bold and italic type, `code` and fenced code
blocks in monospace, lists get hanging bullets or numbers, block quotes are indented, and ---
becomes a drawn horizontal rule β with the markup characters themselves gone from the page. The
result is still selectable text, so Select text (PDF) copies the words without the syntax.
Very large files are refused rather than opened: typesetting a huge log takes minutes and fills
the cache, so a file over the text import limit (64 MB by default) comes back as "Text file is
N MB, over the 64 MB import limit" instead of stalling the app. Raise or lower that limit under
Settings β Storage.
Open an image β picking a PNG, JPEG or WebP opens it as a one-page document with the
picture as the page background, at the picture's own proportions, with an empty layer on top to
draw on. Annotate it like any other document. The image itself is linked, not copied β the
saved .xopp points at the picture where it already lives, so keep it in place β and, as with a
PDF, the first Save asks where to put the .xopp, since an image has no .xopp of its own.
A truncated or corrupt image is refused with a "Couldn't read that image" notice.
MobiXournal also registers as an image handler, so β exactly as with a PDF β it appears in the
Open with / Share sheet of gallery apps, file managers, browsers, and mail clients: tap a
picture there, pick Xournal++, and it opens in a new tab without disturbing the tabs you
already had.
Reopening such a .xopp finds its picture again the same ways desktop Xournal++ does: by
content:// URI, by absolute path, by a path relative to the .xopp's own folder, or from
the sibling file an attached background names. A picture that can't be found leaves those pages
blank with a "Background image not found" notice β the reference itself is preserved, so
putting the file back makes it render again. Saving through Save Asβ¦ β zipped .xopp instead
bundles the pictures inside the .xopp, one archive entry per image-backed
page, so the file carries its backgrounds to another machine.
Import PDF β the menu's Import PDF first asks how the PDF should join the document:
Replace (the PDF's pages become the document, discarding the pages currently open) or
Append (the PDF's pages are added after the pages already open, keeping their annotations β
and it's a single undo away). A .xopp can reference just one background PDF, so appending onto a
document that already has one merges the two into a single joined PDF β the incoming PDF's
pages are added to the end of the existing background PDF, that joined file becomes the document's
one background source, and the appended pages are renumbered against it. Repeat appends keep
composing onto the joined PDF without touching the original files, and the joined PDF is what the
saved .xopp links to (or embeds, for a zipped Save As), so the result reopens in desktop
Xournal++ with every appended page's background intact. Appending onto a brand-new, untouched blank page drops that stray blank sheet. Choosing a
mode launches the picker filtered to PDFs; the import gives you one page per PDF page, each PDF
page rasterised and shown as the page background (Γ la desktop Xournal++ PDF annotation). Draw on top as usual; the strokes are
kept separate from the PDF and the pdf backgrounds round-trip when you Save the .xopp.
The source PDF's reference is recorded in the saved file, so reopening the .xopp later
reloads that PDF and shows the same backgrounds again β no need to re-import.
MobiXournal writes that reference as a relative path whenever it can: if the PDF sits in the same
folder you save the .xopp into, the file records just thepdf.pdf rather than a device-specific
location. That's the portable form β copy the two files to a Linux box together and desktop
Xournal++ finds the background exactly as it does here. When the PDF lives somewhere else
entirely, the full reference is recorded instead, which still works on this device. Nothing to
configure; it just picks the more portable of the two.
Select text (PDF) β for an imported PDF that carries a real text layer (i.e. not a pure scan), the rail's Select slot's Select text (PDF) member lets you drag across the page to select the underlying text; the selected words highlight, and a Copy button puts them on the system clipboard to paste elsewhere. It reads the PDF's own text β no OCR β so scanned image-only PDFs have nothing to select (OCR for those is planned). The selection is view-only and doesn't change the document.
Vertical space β pick Vertical space from the rail to reflow a page: drag down on the page to insert blank vertical space, pushing everything below the grab line down with your finger, or drag up to close a gap and pull that content back. A dashed guide shows the grab line while you drag; only objects whose top edge is below the line move (one the line passes through stays put rather than being torn), and all layers move together. The whole drag is a single undo step, and since it only shifts coordinates it round-trips to desktop Xournal++ unchanged.
Draw β the controls live in a vertical rail down the left edge. It starts with the
tool slots, each standing for a tool or a group of related tools and showing the one that group
is currently set to: Pen, Highlighter, Eraser (partial Β· whole stroke), Line, Rectangle, Shapes
(ellipse Β· arrow Β· double arrow Β· coordinate axis Β· spline), Table, Circuits
(resistor Β· capacitor Β· inductor Β· ground), Logic gates (AND Β· OR Β· NOT Β· NAND Β· NOR Β· XOR Β· XNOR gates), Pan, Select (rectangle Β· lasso Β· select text Β· background copy),
Insert (image), Text (text Β· LaTeX), Vertical space, and Play object. Line and Rectangle get a slot of
their own because they are the shapes you reach for most; every other figure shares the Shapes
slot, whose face starts as the ellipse (the circle). Tap a slot to switch to the tool it shows β
the active slot is highlighted; tap it again once it is the live tool to open a picker over the
group's other members (no long-press needed, though a long-press still works), and picking one both
switches to that tool and re-faces the slot. Those per-slot choices are remembered across app
restarts, so the rail comes back the way you left it. The pop-up buttons β Colour & size,
Shape recognition, Guides, Layers, Zoom, Background, Pages, Audio β each open a small
menu anchored to their own button (opening to the right of the rail); tapping the button again
closes it. A tool slot whose menu offers a choice of tools (any group with more than one member)
wears a small chevron (β) in its bottom-right corner, so a slot that can be re-faced reads
differently at a glance from one that just activates a single tool. The pop-up buttons above do
not wear it: they each open their own panel, not a submenu of alternatives. The Play object slot sits at the very bottom of the rail. Pick Pen or Highlighter and draw with
one finger or the stylus; pen pressure sets stroke width. The Highlighter instead lays down a broad,
constant-width band (pressure-independent) that blends like a real marker β a multiply blend at
desktop Xournal++'s ~47% opacity, so dark ink shows through darkened rather than veiled β and
saves as a highlighter stroke (colour alpha 7f, the byte the desktop app writes) that reopens
the same way in desktop Xournal++. Its
thickness is snapped to desktop Xournal++'s own highlighter tips (1 mm / 3 mm / 7 mm), so a
highlighter drawn here is as thick as one drawn there, whatever the pen's width slots are set to.
Choose a colour and a base width
from the Colour & size pop-up, which holds colour, width and line style in one compact
menu β its button face is a
dot sized to the current width and filled with the current colour. The swatches are
eight colours: Black (#000000), Red (#FF0000), Green (#008000), Blue (#3333CC), Orange (#FF8000), Magenta (#FF00FF), Yellow (#FFFF00), White (#FFFFFF), in that order, each hex taken
from desktop Xournal++'s own palette so a
colour picked here is byte-for-byte the colour it would write there β and the palette itself is
yours to change under Settings β Colors (add, redefine, delete). Its colour half ends with an
editable custom slot (marked with a pencil): tap it to draw with its current colour, or long-press it to
open a picker β a saturation/value square over a hue slider plus a #RRGGBB hex field β to set any
colour. Its size half offers three width slots as one compact row of small boxes, each drawn as a filled dot sized to that
slot's width (the widest slot fills the box, the rest scale down in proportion) under its exact
point size, so the three read as a tip-size ladder rather than three arbitrary letters: tap a
slot to draw with it, or long-press a slot to open a resize dialog (0.5 β 15 pt) that redefines
that slot's width β drag the slider for a broad sweep, tap β / + to nudge it 0.1 pt at
a time, or type an exact point size into the text field. That same palette β swatches and the
custom slot β is what the text-box dialog and the selection recolour menu offer, so the three
always agree. The custom colour, the three widths,
and the colour/width you were last drawing with are all remembered across restarts,
so the app reopens with the pen you left off with. Each tool keeps its own colour and width
across a switch: the pen comes back to the pen's, the highlighter and the figures to theirs β and
that holds whichever way you switch (rail slot, keyboard shortcut, barrel button),
so picking the pen after a fat figure or highlighter draws with the pen's own medium width again
instead of inheriting theirs. New strokes land on the active layer
(see Layers below) of whichever page you draw on.
Line & shapes β the rail's Line, Rectangle, Shapes, and Table slots offer Line,
Rectangle, Ellipse, the STEM figures (Triangle, Square, Rhombus, Pentagon,
Hexagon, Star), Table, Coordinate axis, Spline, and the two arrow tools (Arrow, Double arrow);
Line, Rectangle, and Table are one tool each; the rest share the Shapes slot (with the figures first and the
arrows separated by a divider; order and visibility can be customised in Settings β Figures). Pick
one and drag from one corner/endpoint to the other; a live preview follows your finger and the
shape commits on release. The Table tool lets you draw or insert custom grid tables: configure the number
of rows and columns directly on the canvas via the contextual bar (or under Settings β Figures), toggle
Header to add a relational double separator line under the first row (the relational database schema standard),
then drag to size it interactively, or tap Insert to place it centered in the visible viewport. Tables are stroked with
figure styling (adjustable shape width, color, and line style) and round-trip losslessly to desktop Xournal++ as standard strokes.
Shapes are saved as ordinary strokes in the current pen colour and the
shape width β a width of its own, kept separate from the pen's and defaulting to the middle
size slot, the same one the pen starts at (the default slot is set in Settings β Figures), so
a fresh shape and fresh handwriting come out the same weight; the wide slot is left to the
highlighter. A shape draws at that width directly β it does not taper with pen pressure the way a
freehand stroke does, so with pressure on a shape can look thicker than a light pen stroke (the
Figures section is where you compensate); a shape and a fully-pressed pen match. Set the width from
the Colour & size pop-up while a line/shape tool is active (tap a width slot, or long-press one
to redefine it); that same pop-up carries the Line style submenu β Solid, Dashed,
Dash-dot, Dotted β so the pen and the figures can be dashed without leaving it. Width and
style are remembered across restarts. The result round-trips to desktop Xournal++ like any other stroke. A double arrow gets a head at each
end; a coordinate axis puts its origin where the drag started and runs an arrowed x and y axis out
to the drag's width and height. The Spline tool is for a smooth curve through points you place one
at a time. Tap to drop a control point; drag away from a tap instead of lifting to pull out
a tangent handle that bows the curve through that point (lift where you want the curve to lean).
Keep tapping to extend it β the whole curve previews live as you go, with a dot on every control
point, a line through each tangent handle showing how hard that point is bowed, and a dashed
rubber band from the last point to a hovering stylus, so you can see where the next tap will take
it. While a curve is open, a bar shows how many points it has and offers Finish (disabled
until there are two, since a single point draws nothing), an undo button that drops just the
last point, and a close button that discards the whole curve. Double-tap or Enter also
finishes it, Backspace drops the last point, and Escape or Back throws it away;
switching to another tool commits whatever you have so far. The result is one ordinary constant-width stroke in
the current pen colour and width, so it round-trips to desktop Xournal++ like any other stroke.
The Colour & size pop-up sets Line style (Solid, Dashed,
Dash-dot, Dotted) as a row of chips, as well as the
colour and the tip size β there is no separate Style slot any more, so the three are one tap
from the rail. The line style
applies to all shapes and strokes drawn with the line/shape tools and saves on the <stroke>
element (style), reopening the same way in desktop Xournal++. Fill is gone: the app no
longer offers it, and strokes drawn here are never flooded β a .xopp that already carries
fill on a stroke still opens, renders and re-saves with it untouched.
Electronic circuits β the rail's (and secondary top bar's) Circuits tool offers fundamental passive circuit components: Resistor (standard 6-peak zigzag between lead wires), Capacitor (parallel plates with symmetric terminal wires), Inductor (smooth 4-loop coil), and Ground (3-tier stepped earth/chassis ground symbol). Drag from the start terminal to the end terminal; the component dynamically scales and rotates along your drag vector with clean engineering proportions. Drawn in the active shape width and pen colour, circuits save as standard constant-width strokes that round-trip losslessly to desktop Xournal++.
Logic gates β the Logic gates tool provides the complete IEEE-standard digital logic gate set for computer science, digital logic design, and boolean algebra: AND, NAND (with inversion bubble), OR, NOR, XOR (with dual curved input arcs), XNOR (dual curved input arcs plus output inversion bubble), and NOT (inverter triangle + bubble). Drag from the input side toward the output; the gate is drawn with symmetrical input leads and an output wire, oriented precisely along your drag vector. Like all figures, logic gates round-trip cleanly to desktop Xournal++ as standard strokes.
Shape recognition β turn it on from the rail's Shape recognition button (the triangle; it tints while on, and the state is the same persisted setting as Settings β Stylus β Shape recognition, so you can flip it mid-page without leaving the editor) and a freehand stroke is snapped, the moment you lift, to the shape it clearly resembles: a straight line, a triangle, a rectangle, or a circle. This is desktop Xournal++'s own shape recognizer, ported line for line with its thresholds intact, so a stroke is judged here exactly the way it is judged on the desktop β and, as there, that means circles rather than ovals: an ellipse stroke is left as drawn. Anything else the recogniser doesn't recognise β handwriting above all, but also arrows and open polylines, which upstream doesn't attempt β is kept exactly as you drew it, and a stroke under 40 pt across is never snapped at all. A rectangle you draw roughly upright is squared to the page axes, and the corners of every recognised shape are rebuilt from where the fitted lines cross, so they come out sharp instead of wobbly. The result is one ordinary constant-width stroke, so it round-trips to desktop Xournal++ like any other. The toggle is on by default and applies to the pen and the highlighter alike β as on desktop, where both tools carry the recogniser β so a straight highlighter line snaps to a line too.
Snapping β two optional aids under Settings β Editor. Snap to grid pulls the start and end of a shape drag onto the page background's ruling, so lines and boxes line up with the paper: a graph or dotted page snaps both axes to its squares, a lined/ruled page snaps only the vertical position (it rules no vertical lines), and a plain page snaps nothing. Snap rotation makes the selection's rotate handle step in 15Β° increments β handy for turning something exactly upright or square. Both are off by default, and neither changes what is written to the file: the result is still ordinary stroke geometry.
Drawing guides (setsquare, compass & protractor) β the Guides rail button lays a virtual instrument on
the page: a Setsquare (a 30/60/90 geometry triangle), a Compass (a circle), or a Protractor (a graduated semicircular scale with 5Β°/15Β° ticks and degree labels). Anything drawn near the protractor's flat diameter rules straight, near its curved rim snaps to a circular arc, and vectors drawn through its body snap to 15Β° radial angles. Anything you
draw within about a quarter-inch of the instrument's edge is ruled onto it, so a freehand stroke
along the setsquare comes out perfectly straight and a stroke swept around the compass comes out as
a clean arc of that radius; move the pen away from the edge and it draws freehand again. Slide the
guide with a finger placed on its body β inside the setsquare's shaded triangle, or on the
compass's centre dot β and drag its amber tip handle to re-pose it: that rotates and resizes the
setsquare (with Snap rotation on it lands on 15Β° steps) and opens or closes the compass. The
edges themselves are left free to draw against, so ruling along the outside of the setsquare never
drags it out from under your pen, and you can go on holding it steady while you draw. Choose
Off to take it away. The guide is purely an input aid: it is never written to the .xopp file,
so what you draw with it is ordinary stroke geometry. Which guide is out is remembered across
app restarts.
Erase β tap the rail's Eraser slot and drag over strokes. Long-press the slot to pick
which eraser it stands for: Eraser (partial) rubs out just the part of a stroke the eraser
passes over, splitting it into the surviving pieces; Eraser (whole stroke) removes any stroke
the eraser touches entirely. Like every tool slot, the choice is remembered across restarts. The
eraser has no size of its own β its tip follows the width slots in the Colour & size pop-up:
the tip's radius is the selected pen's
full width, so the rubber is twice as wide as the ink it removes β wide enough to bite, narrow
enough to erase precisely β and the three slots still give three clearly different tips. It is
measured in document points, so it rubs out the same amount of ink whatever the zoom. A thin black
circle shows exactly where the tip's edge falls β it follows a hovering stylus, and follows the
contact point while you rub (finger touches included). When you erase by holding the stylus
barrel button, the circle appears the moment the button goes down, so you can see the tip's reach
before touching the page. It is on-screen chrome only: it is never part of the page and never
written to the .xopp file. The eraser only affects the
selected layer β ink on other layers is left alone β and hidden layers are never erased. If your stylus has an eraser tip (the flip-over
end), using it erases no matter which tool is selected; so does holding the stylus barrel button
(configurable β see Settings) β and the tip circle appears the moment the button goes down while
the pen hovers, so you can see what you are about to rub out before touching the glass. The button
is understood however your pen reports it: the standard stylus button bits, the
barrel-button key events a Bluetooth pen sends on Android 14 and later, or a plain right-click
from a pen the tablet only ever sees as a mouse (which is how some tablets present a pen they never
promoted to a stylus). Pressing it mid-stroke hands the rest of that stroke to the eraser β the
ink already drawn stays, and everything the pen passes over from then on is rubbed out β so holding
the button erases whether you press it before the tip lands or while writing; letting go does not
bring the stroke back. Double-clicking the barrel button with the pen lifted off the
glass runs its own action β undo by default (see Settings).
Layers β the Layers pop-up manages the visible page's layers (top of the list = top of the
page). Each row can make the layer active (tap its name β new ink lands there, marked with a
filled dot), show/hide it in the editor (the eye toggle β hiding is view-only and never changes
the file), reorder it up/down (z-order), merge it down into the layer below (the merge
button β the two layers' contents combine in z-order, the lower layer keeps its name, and the
emptied upper layer goes away; disabled on the bottom layer), rename it, or delete it (a
page always keeps at least one layer). Add layer puts a fresh empty layer on top. With something selected, each row
also shows a move-selection-here button. Layer names round-trip via the <layer name> attribute;
every structural change is undoable.
Stylus β the app is stylus-first. Rest your palm on the screen while you write: once the pen is down, finger/palm touches are ignored for drawing (a second finger still pans). A hovering stylus shows a preview ring where the tip will land. Pen pressure sets stroke width, with a configurable feel, tapering more deeply at a light touch to match desktop Xournal++. Handwriting is smoothed as you write β digitiser wobble in both position and pressure is filtered out, and redundant points are dropped when the pen lifts, so strokes look clean and files stay small. All of this is tuned in Settings below.
Select β the rail's Select slot selects objects the way desktop Xournal++ does. The marquee shape is the tool itself: long-press the slot to pick Select rectangle (drag a box; every object fully inside is selected), Select lasso (trace a free-form loop; everything wholly inside is selected), Select text (PDF), or Select background (flatten). Both shapes allow a few points of slack at the edge, so tracing tightly around a hairline stroke still catches it. A marquee only picks objects on the active layer, as on the desktop β switch layers to select the ink on another one. Or tap a single object to select just that one. Selected objects get a dashed outline with handles:
.xopp format, so they can't be rotated).Object selection edits are undoable, and so is a background Cut. A background Copy only fills the clipboard; the later paste is undoable. (Selection is per page; two-finger pan still works.)
Text β pick Text from the rail's Text slot and tap where you want a text box; a dialog
takes the content from the keyboard and lets you style it: font family (Sans / Serif /
Monospace), bold, italic, a size slider (6β96 pt), and a colour β the same picker
the pen uses, so the custom slot is shared with it. Tapping
an existing text box reopens it for editing with all of that prefilled from the box (clearing the
text deletes it). Every property round-trips to and from desktop Xournal++ via the .xopp
<text> element. (Underline isn't offered β the format can't store it.)
Image β pick Image and tap where the image should go; the system picker opens, and the chosen picture is placed at that point (scaled to a sensible size).
LaTeX β pick LaTeX (the Text slot's second member) and tap to place a math image; a dedicated formula dialog opens with a STEM symbol palette (Calculus, Greek letters, Operators, and Physics shortcuts) for quick insertion at the cursor, and it's rendered as real math.
Undo / Redo β the arrows in the top bar undo and redo edits, one gesture at a time (drawing, erasing, and adding/editing text/image/LaTeX are all undoable). They enable and disable as history allows; opening a file starts fresh history. History is 200 edits deep β past that the oldest step is dropped, so the most recent edits always stay undoable without the stack growing forever.
Scroll β drag with two fingers to move around the page stack, or pick the Hand tool from the rail to pan with one finger (handy on a stylus). A quick one-finger flick keeps the pages gliding with momentum and coasts to a stop β the faster the flick, the much farther it carries β while a two-finger pan stops the instant you lift. Touch down again to halt a glide at once. With the Hand tool, a double-tap navigates: tap twice on the left edge to jump to the previous page, on the right edge for the next page, or in the centre to toggle full-page view (hides the top bar and side toolbar for a distraction-free canvas; double-tap the centre again to restore them). A PDF-style scroll thumb rides the right edge whenever the document is taller than the screen: drag it to page quickly through a long document (a page-number bubble shows where you are as you drag). A small grip bulges out of its centre so it's easy to grab. It sits faint while idle and brightens as you scroll; only the thumb itself grabs touches, so the rest of the page's right margin still takes ink. A page counter ("3 / 12") sits permanently in a corner of the canvas β the bottom-right by default, and movable from Settings βΈ Appearance β so you always know which page of how many you're on; it stays put in full-page view, where the bars are hidden. Directly above it a zoom badge ("125%") in the same pill shows the current zoom level at a glance, and tapping it resets the zoom to 100%. With a mouse connected, the scroll wheel scrolls the document vertically β wheel down moves further down the pages, the same direction as dragging the scroll thumb down β and leaves the zoom level alone.
Back button β the Android back button (or back gesture) navigates instead of quitting. Each press steps one layer out of wherever you are, and only the last press leaves the app. Dialogs and pop-up menus close on back as you'd expect; beyond those, back cancels an unfinished spline, then leaves a text edit or drops a selection, then clears picked pages and leaves the page-overview edit mode, then restores the chrome from full-page view β and finally exits. In Settings, back returns from a section to the settings index, exactly like the on-screen back arrow, and a second press closes Settings back to your document. Back is ignored while a document is opening or saving, so a slow transfer can't be interrupted half-way.
Zoom β pinch with two fingers anywhere on the canvas to zoom in or out; the point between your fingers stays put as the page grows or shrinks, and you can pan at the same time in the one gesture. The % button on the rail also opens a zoom pop-up with β / + buttons; tap the percentage to reset to 100% β or tap the zoom badge above the page counter for the same shortcut without opening anything. Zooming wider than the screen lets you pan sideways. Zoom ranges from 25% to 1000%, so you can work on fine detail; ink stays sharp at every level. PDF page backgrounds stay sharp too: past a certain zoom only the part of the page you can actually see is re-rendered, at full screen resolution, so PDF text is crisp all the way to 1000%. A freshly zoomed or panned area may look soft for a moment before the sharp version lands.
Background β the grid button on the rail opens the page-background pop-up, which sets the
paper ruling of the page in view: Plain (bare sheet), Lined, Ruled (lined with a red
margin), Graph, or Dotted. The current style is check-marked; picking another re-rules the
page immediately (an undoable edit) and round-trips via the <background style> attribute. The
ruling is drawn in desktop Xournal++'s own paper colours β lined rules in its xopp_dodgerblue,
graph/dotted in its xopp_silver β so the paper looks the same on both. On a
PDF or image-backed page there's no solid sheet to re-rule, so the items are disabled.
Pages β the document button on the rail opens the page navigator: it shows Page N / M with β / βΆ to jump to the previous/next page, plus Add page (a blank page after the one in view β it is born at the default page size and keeps the current page's paper ruling, but a PDF/image background is dropped to a plain white sheet so the new page is genuinely blank, not a copy of the page underneath) and Remove page (the one in view; the last page is never removed). Add and remove are undoable.
.xopp, so it round-trips to desktop Xournal++. The pen is
never a candidate for the lift, so drawing on a grid page is unaffected; sliding your finger
before the press registers pans as usual..xopp. The selection is view-only state: it clears when
you return to 1 page per row, and after any page add/remove/reorder (the indices have moved).<page width= height=> attributes to desktop
Xournal++.Settings β the top-bar menu opens Settings, a list of sections β Stylus, Editor, Toolbar, Figures, Colors, Shortcuts, Navigation, Appearance, Storage, Backup and About. Tap a section to open it as its own page; back returns to the list, and back from the list returns to the editor. Your choices persist across restarts. Under Stylus:
755 while no
motion event of the stroke mentions a button at all β and because the button then exists only on
the key stream, a press stays latched until the key comes up rather than being cleared by the
first touch. Holding it applies while you draw as well as before: pressing it mid-stroke
turns the rest of that stroke into an erase. If holding your pen's button still does nothing,
open β° menu β Pen diagnostics (below) and press the button over the canvas: if nothing at all
appears, the tablet is swallowing the button before any app sees it β on some Honor/Huawei styli
the side button is wired into the vendor's own apps only, and no setting in this app can reach
it. That is also the pen whose press exists only as a click (its firmware reports one press for
a whole double-click, and nothing at all for a single tap), so the Barrel button choice above
is inert on it and Barrel double-click below is the setting that matters. Such pens still have
their own paths: the flipped-over eraser end, and the keyboard shortcuts set under Shortcuts
below. If the log shows a key you do not expect, send it on β that is a path the app can learn.stylus/mouse/finger), button bits, key codes and source flags. It is the
way to find out what a stylus really sends, and it stays on the canvas because that is the only
place the pen's events arrive: press and hold the side button while drawing and read the last few
lines. The log also carries lines the app itself adds β CLICK -> toggle eraser, or CLICK swallowed (same gesture) β which say what it did with the press, next to what arrived, so a dead
button can be traced to the pen, to the tablet, or to the app's own reading of the event.
Copy puts the whole log on the clipboard if you want to send it on, and Clear
empties it without closing the panel; back or the menu closes it. It is a debugging aid, not a
preference β it starts off every launch and nothing about drawing changes while it is on..xopp. Lowering it keeps
files small. Existing strokes are unaffected β the setting applies to what you draw next.
The budget is also capped in page units, so a stroke drawn zoomed out or in the multi-page
overview stores the same detail as one drawn at 100% β zooming out never costs you precision.Under Shortcuts β the keyboard shortcuts, gathered in their own section rather than mixed in with the input behaviours:
Optimizing for graphics tablets (tavoletta grafica): MobiXournal works seamlessly with external USB (via OTG) and Bluetooth drawing tablets (such as Wacom, Huion, XP-Pen, and Gaomon). Recommended setup:
S or M) to balance them with your average pen pressure, or disable pressure sensitivity in Settings β Stylus for completely uniform strokes across pen and figures.Under Editor:
Under Toolbar:
Under Figures:
Under Colors:
Black (#000000)), with an edit button opening the HSV/hex picker and a delete button
removing it. Add colour appends a new swatch (the grid is capped so it stays a grid), and
Restore default palette puts back the eight defaults. The last remaining colour cannot be
deleted β an empty palette would leave the pickers with nothing to pick β and deleting a colour also
drops its keyboard shortcut, so no key points at a swatch that no longer exists.Under Navigation:
Under Appearance:
Under Storage β two budgets that bound what opening documents costs on disk and in memory:
Under Backup β export and import preferences across devices and versions:
.json backup file via the system file picker.Under About β what this build is and where it came from:
LICENSE, and the page links to the GPL and to the
Xournal++ project..xopp editor
this codebase continues, plus a plain statement that this app is unofficial and not affiliated
with the Xournal++ authors.Export PDF β the menu's Export PDF flattens the whole document to a PDF: each page is
drawn at its true size with its background (a PDF page, an image, or a ruled sheet) and every
stroke and element merged on top, then written to the location you pick β pre-filled with the
open document's own name and a .pdf extension, so notes.xopp exports as notes.pdf and
the export lands beside the document it came from (a document that has no name of its own yet is
offered as Untitled.pdf). Pages backed by an
image keep that picture in the export, at print-usable resolution. When a page came from an imported
PDF, its original page is kept as vector content and your annotations are laid over it as
vectors too β so re-exporting an unchanged PDF stays about its original size and sharpness instead
of ballooning from a rasterised copy. Use this to share an annotated copy; Save keeps the
editable .xopp.
Fonts in generated PDFs β when MobiXournal generates a PDF page for you (the text-import path), it
typesets with DejaVu Sans (plus its bold, oblique and bold-oblique companions, used
for markdown emphasis) and DejaVu Sans Mono, which ship inside the app. Because they are
embedded (and subsetted) into the PDF, imported text in Cyrillic, Greek, CJK, or box-drawing
characters renders the same on any viewer without those fonts installed, and the file only carries
the glyphs it actually used. A character even DejaVu doesn't have is drawn as a οΏ½ placeholder
rather than failing the export. Both fonts are freely licensed; the full licence ships with the app
and is checked in at app/src/main/assets/fonts/LICENSE.txt.
Audio (record & replay) β the rail's Audio slot records the microphone while you write,
and every stroke you draw is tagged with the moment in that recording it was started. Tap
Record to start (Android asks for microphone permission the first time), and Stop
recording to finish. Then pick the Play object tool from the rail and tap any stroke to
hear the audio from the instant that stroke was drawn β the same fn/ts stroke tagging desktop
Xournal++ uses, so recordings made there replay here and vice versa. Stop playback in the same
pop-up silences it.
Audio is not stored inside the .xopp β it lives in a .wav file beside it, exactly as on
the desktop. Android only grants an app access to the one file you picked, not its folder, so the
first time you record, use Choose audio folder⦠in the Audio pop-up and pick the folder your
.xopp files live in. MobiXournal then writes new recordings there when you save, and loads a document's
recordings from there when you open it. Until you choose a folder, recording and playback still
work for the session, but the .wav never leaves the app β so a file you take back to the desktop
won't have its audio.
Save β the menu's Save writes the whole document back out to a .xopp file, preserving
every page, layer, background, and element β strokes plus the text, images, and LaTeX images you
authored on-device. Save writes in whichever format you last chose in Save As⦠(see below):
it starts as Original, and once you Save As Zipped, every later Save stays Zipped until
you switch back. Opening a file adopts the format it was stored in.
Save writes straight back to the file the tab came from β no picker β whether that file is
on local storage or a mounted remote share; you're only asked for a location when the tab has no
file yet (or the grant on it has lapsed). The document is encoded locally and then pushed across
in one pass behind a "Savingβ¦" note, so a slow or broken link can never leave a half-written
.xopp on the far end.
Save Asβ¦ β the menu's Save Asβ¦ opens a dialog to name the file and pick its format.
Whatever you type is saved as a .xopp: the name you enter is given the .xopp extension
(and an existing extension is replaced), so a Xournal++ document never lands on disk under a
name β or a type β the system and desktop Xournal++ can't recognise as one:
.xopp (gzip-compressed XML). For a PDF-backed
document the PDF stays linked by location (its path/URI), so the .xopp is small and
reopening it reloads that PDF from where it lives β the interchange-safe default..xopp with the PDF embedded inside it, so
the document is fully portable and moves as a single file. It reopens with its background intact
in MobiXournal itself (the PDF travels in the same file) as well as on desktop Xournal++.
The file on disk is the only source of truth β there's no cloud, account, or custom format.
Every package and what it holds is documented, file by file, in
docs/architecture.md β the authoritative layout. The app's Kotlin
sources live under app/src/main/java/com/mobixournal/ (format/, io/, render/, audio/,
tabs/, panes/, ui/, plus MainActivity.kt), with JVM unit tests under app/src/test/ and
the containerized build in Dockerfile, compose.yaml and scripts/build.sh.
MobiXournal is free software under the GNU General Public License, version 2 or
later β the same licence as Xournal++, the project it is
based on. This is an unofficial derivative: not affiliated with, endorsed by, or maintained by
the Xournal++ authors. The app icon is this project's own artwork. The full text is in
LICENSE. It comes with no warranty.
Kotlin
98.3%
Python
1.4%