Skip to content

Repository files navigation

Graphics Drawing

A focused native Android drawing canvas for stylus and USB graphics-tablet input.
Draw with pressure-sensitive brushes, geometric shapes, layers, gestures, and a lightweight programmatic View-based interface.

Android Kotlin Minimum SDK 26 In development

1. Project status

This repository is a working Android drawing app with a USB input path specifically adapted to the VEIKK VO1060. The codebase already contains the implemented Stage 1 drawing-performance improvements, layer/cache improvements, verified VO1060 report parsing, auxiliary-control parsing, and the one-minute in-app raw-capture diagnostic option.

Important: FEATURES_TO_IMPLEMENT.md is the single source of truth for everything that is still planned, incomplete, deliberately unsupported, or not physically verified. Do not use the old implementation-report/stage-plan files from previous versions; their implemented content has been consolidated here and in this README.

2. Current working features

Drawing

  • Freehand touch drawing.
  • USB VEIKK VO1060 pen drawing.
  • Pressure-sensitive stroke width.
  • Pen, Crayon, and Ink brush engines.
  • Adjustable brush size, opacity, and density where supported.
  • Eraser mode and clear-canvas action (clears the active layer only).
  • Undo/redo with a maximum 50-entry undo history.
  • Optional floating draggable undo button and two-finger undo gesture.
  • Pinch zoom, pan, and two-finger canvas rotation.
  • Viewport state is retained by DrawingViewModel across Activity recreation/orientation changes.
  • Hand drawing mode for finger input independent of stylus mode.
  • Reset Zoom action to return the canvas to its auto-fit state.

Toolbar and menus

The toolbar is a fixed floating bar at the top of the drawing screen. It contains:

  • Main menu (☰): Erase, Hand drawing, Shapes, Clear.
  • Brush button: Opens the brush browser.
  • Color swatch: Opens the color picker.
  • Layers button (▤): Opens the layer dialog.
  • Overflow menu (⋮): Save, Settings, Undo, Redo, Reset Zoom.

The toolbar can be hidden (long-press the Clear button to restore it). Toolbar visibility state is persisted across sessions.

Color picker

  • HSV color model with an interactive hue bar and color square.
  • Preset color swatches for quick selection.
  • Live preview of the selected color.
  • Cancelling or backing out of the color picker does not change the active color.

Brushes and stroke rendering

  • Brush renderers are isolated under graphicsdrawing/drawing/brushes/.
  • Brushes are discovered automatically at startup; the registry does not require a hard-coded brush list.
  • StrokeSmoother is applied only to brushes that opt into common smoothing; Crayon explicitly opts out because it generates its own particle geometry.
  • Historical touch samples are fed into the stroke pipeline before the current MotionEvent sample, improving point density without an artificial delay.
  • A shared BrushEngine boundary isolates brush lookup, optional common smoothing, and brush rendering.
  • StrokeSmoother works at render time while raw points remain authoritative for stored strokes, undo/redo, and document coordinates.
  • Stage 1 performance work is already in the code: Crayon opts out of redundant common smoothing, reusable Crayon rendering buffers are used, per-render stroke.points.toList() copying was removed, Pen pressure statistics are cached per input sample, and the Ink width buffer is reused.
  • Stage 2/3 rendering improvements are implemented: Pen/Ink opacity is isolated per stroke to avoid overlap darkening, constant-width paths use smooth cubic interpolation, long Crayon strokes use persistent in-progress rendering caches, Crayon particle sampling avoids per-sample Random allocation, and Ink variable-width rendering uses a single filled outline path to remove the fast-stroke chain-link/bead artifact.
  • Layer-render caches and incremental/composited bitmap paths are implemented in DrawingEngine/LayerManager to reduce repeated full-document redraw work.

Shapes

The current shape tools are:

  • Straight line
  • Square
  • Rectangle
  • Circle
  • Oval
  • Rounded rectangle

Simple geometry recognition is implemented. The Advanced (AI) option is present in Settings as Coming Soon and is not active.

Layers

  • Multiple layers.
  • Active-layer selection.
  • Layer visibility, opacity, and clipping state.
  • Visual stack is maintained top-to-bottom with recalculated layer numbering.
  • Adding a layer inserts it above the current layer.
  • Eye toggling updates the layer dialog without closing it.
  • Per-layer rendered bitmap caches reduce repeated stroke rendering.
  • Full-document/layer previews fit the complete layer content into the thumbnail area.
  • Undo/redo includes layer and stroke actions.

Settings

Settings are built programmatically and currently contain these sections, in this order:

  1. Shape Recognition
  2. Canvas
  3. Display
  4. Advanced

The Advanced section is intentionally at the bottom. It contains the development/hardware diagnostic option VEIKK Raw HID Capture.

Current settings include:

Shape Recognition

  • Simple Geometry — Uses math to detect lines, circles, rectangles, and triangles. Fast, works offline, no extra download needed.
  • Advanced (AI) — Coming Soon. Will use on-device AI for better accuracy on messy or rotated strokes.

Canvas

  • Pressure Sensitivity — Varies stroke width based on stylus press force. Default: on.
  • Stroke Smoothing — Applies light smoothing to reduce hand tremor. Default: off.

Display

  • Show Cursor Crosshair — Shows the custom crosshair at the exact point the stylus draws. Default: on.
  • Full Screen Mode — Hides the Android status and navigation bars. Default: off.
  • Dark Mode — Uses a dark canvas, menus, and controls with light text and icons. Default: off.
  • Floating Undo Button — Shows the draggable undo button on the drawing screen. Default: on.
  • Undo Gesture — Undo the latest stroke with a two-finger tap. Default: on.

Advanced

  • VEIKK Raw HID Capture — Creates two TXT files in Downloads/VEIKK: one for VO1060 pen reports, one for raw USB HID reports including tablet-key events. Automatically turns off after 1 minute.

Save/export

  • The Save action exports the composited visible drawing as PNG through Android MediaStore.
  • Export location: Pictures/VEIKK Drawings.
  • The current app does not reopen editable project/document files.

3. Verified VEIKK VO1060 Android input

The current code is based on physical raw captures from the target device, not only on the supplied Windows-driver/reference values.

Pen report

Field Current verified value
Pen report ID 0x02
Report length 10 bytes
X bytes 2–3, little-endian
Y bytes 4–5, little-endian
Pressure bytes 6–7, little-endian
X range 0..32767
Y range 0..32767
Pressure range 0..8191
Hover 0xC0
Contact/drawing 0xC1
Pen Button 1 0xC2
Pen Button 2 0xC4
Out-of-range observed 0x80
Tilt candidate X signed byte 9
Tilt candidate Y signed byte 8

The current parser clamps X/Y/pressure to the verified physical ranges and normalizes pressure through the isolated PressureProcessor/PressureCurve path. The pressure curve is currently 1:1.

Auxiliary control report

A separate 8-byte Report ID 0x03 stream is parsed independently from the 10-byte pen report.

Control Verified code
Tablet Button 1 0x0113
Tablet Button 2 0x0108
Tablet Button 3 0x004B
Tablet Button 4 0x004E
Dial Center 0x001A

The diagnostic capture identified the stream on interface 1, endpoint 0x82. These are treated as VEIKK/VO1060-specific control codes; the app does not assume they are generic HID keyboard usages.

Windows driver usage

The supplied Windows package is reference material only. Windows .sys, .dll, and .exe components are not executed or embedded as Android drivers. The Android implementation uses the Android USB/HID input path and the verified physical report structure.

Secondary reference values such as 13-byte reports, 50800 × 31750 coordinate ranges, and similar Windows-driver assumptions must not override the physical Android captures above.

4. Current tablet mapping status

Implemented and working. The VEIKK VO1060 is mapped to the Android device/app input area used by the drawing View. The tablet pointer is not restricted to the document/canvas content. It works throughout the app's drawing View, and the pointer remains usable while the canvas is zoomed, panned, or rotated.

The current input flow is:

Physical tablet
  -> raw VO1060 report
  -> verified parser
  -> normalize X/Y
  -> TabletMapper
  -> Android app/drawing View coordinates
  -> pointer crosshair / app-space position
  -> existing inverse canvas transform
  -> document coordinates for drawing

TabletMapper uses the current Android View width/height as the tablet mapping target. The canvas/document transform is applied after the tablet position has been established in View/screen space. This is why changing canvas zoom, pan, or rotation does not move or disable the tablet pointer.

Android portrait/landscape changes also work because the mapping uses the View's current dimensions rather than a hard-coded physical screen resolution.

Important distinction

  • Tablet → Android app/View mapping: implemented and working.
  • Tablet pointer inside the app: implemented and working.
  • Pointer while canvas is zoomed/panned/rotated: working.
  • Pointer after Android screen orientation changes: working.
  • Tablet → document/canvas coordinates: handled by the existing inverse canvas transform after app/View mapping.

This is not a pending feature. Do not reimplement or replace this mapping architecture unless a future bug or new requirement specifically requires it.

5. Current tilt status

Tilt bytes are already carried through the current input/drawing data structures:

  • byte 9 is treated as the X-direction candidate;
  • byte 8 is treated as the Y-direction candidate;
  • the current parser exposes normalized directional candidates in -1..1 using signed-byte scaling.

However, the following are not confirmed/calibrated yet:

  • exact neutral offsets;
  • exact physical angle represented by a raw value;
  • full physical tilt range;
  • correct gain for the advertised 60° range;
  • final brush behavior based on tilt.

Tilt-aware brush rendering is therefore still pending and must not be described as fully calibrated functionality.

6. Raw diagnostic capture

Settings → AdvancedVEIKK Raw HID Capture starts a maximum one-minute capture session.

When active and the Drawing Activity is foreground with a connected VO1060, the app creates two TXT files under Downloads/VEIKK:

  • vo1060_raw_YYYYMMDD_HHMMSS.txt — the pen stream.
  • vo1060_usb_diag_YYYYMMDD_HHMMSS.txt — the USB HID diagnostic stream, including auxiliary/tablet-key reports received from the active endpoint.

Safety behavior already implemented:

  • Off by default.
  • Recording starts only when the drawing Activity is visible and a VEIKK tablet is actually connected/claimed.
  • Automatically expires after 60 seconds.
  • Leaving the drawing Activity finalizes the files.
  • Disconnecting the tablet finalizes the files.
  • Capture is buffered rather than forcing a disk write on every USB report.
  • Raw capture is independent of the drawing engine and is not required for normal drawing.
  • USB debugging is not required after the APK is installed; capture is written to user-accessible storage.

7. Current project structure

Path Responsibility
graphicsdrawing/MainActivity.kt Main screen lifecycle, settings application, drawing view setup, and VO1060 input hookup.
graphicsdrawing/SettingsActivity.kt Programmatic Settings UI and SharedPreferences-backed settings.
graphicsdrawing/drawing/DrawingEngine.kt Stroke lifecycle, rendering, shape drawing, layer composition, cache handling, bitmap generation, clear, undo, and redo.
graphicsdrawing/drawing/BrushSettings.kt Active brush/tool state.
graphicsdrawing/drawing/StrokeSmoother.kt Common render-time point smoothing for brushes that opt in.
graphicsdrawing/drawing/brushes/ Pen, Ink, Crayon renderers plus brush interfaces/definitions/registry.
graphicsdrawing/model/DrawingModels.kt Drawing points, strokes, and layers.
graphicsdrawing/model/DrawingViewModel.kt Lifecycle-retained drawing state, engine, mapper, document dimensions, and viewport state.
graphicsdrawing/layers/LayerManager.kt Layer storage, visibility/opacity/clipping state, and 50-entry undo/redo history.
graphicsdrawing/input/VeikkUsbInput.kt USB discovery, permission, connection lifecycle, packet reading, pen parsing dispatch, auxiliary report dispatch, and raw-capture hooks.
graphicsdrawing/input/VeikkVO1060ReportParser.kt Verified 10-byte VO1060 pen report parser.
graphicsdrawing/input/VeikkAuxiliaryEvent.kt Separate parser/model for Report ID 0x03 auxiliary controls.
graphicsdrawing/input/TabletSample.kt Parsed tablet sample including raw values, normalized pressure, tilt candidates, and verified pen button/contact state.
graphicsdrawing/input/TabletMapper.kt Maps raw VO1060 coordinates to Android app/View coordinates using current View width/height.
graphicsdrawing/input/StrokeInput.kt Normalized sample passed into the drawing/stroke pipeline.
graphicsdrawing/input/VeikkCaptureController.kt One-minute user-controlled raw-capture lifecycle and file-session coordination.
graphicsdrawing/input/VeikkRawCapture.kt User-accessible VO1060 pen report file output.
graphicsdrawing/input/VeikkUsbDiagnosticCapture.kt User-accessible USB HID diagnostic file output.
graphicsdrawing/input/VeikkRawReportLogger.kt Parsed/raw logging support used by the diagnostic path.
graphicsdrawing/input/VeikkDebugConfig.kt Debug configuration for tablet input.
graphicsdrawing/input/MultiFingerGestureDetector.kt Two-finger zoom/pan/rotate and optional undo gesture detection.
graphicsdrawing/pressure/ Pressure normalization and isolated pressure curve abstraction.
graphicsdrawing/ui/TabletDrawingView.kt Drawing surface, touch input, tablet input, viewport transform, pointer display, and drawing/layer controls.
graphicsdrawing/ui/ToolbarController.kt Toolbar actions, settings/persistence wiring, dialogs, floating undo bubble, and export actions.
graphicsdrawing/ui/TopBar.kt Fixed floating toolbar with main menu, overflow menu, brush/color/layer buttons, and dismissible panel menus.
graphicsdrawing/ui/ToolDialogs.kt Shape and layer dialogs plus previews/icons.
graphicsdrawing/ui/BrushDialog.kt Brush browser, previews, and per-brush option controls.
graphicsdrawing/ui/ColorPickerDialog.kt Custom HSV color picker with hue bar, color square, and preset swatches.
graphicsdrawing/ui/ShapeType.kt Available shape enum (Off, Line, Square, Rectangle, Circle, Oval, Rounded Rectangle).
graphicsdrawing/storage/DrawingSaver.kt PNG export through Android MediaStore.
app/src/main/AndroidManifest.xml Android application manifest.
app/build.gradle.kts Android/Kotlin configuration, SDK levels, Java 17, dependencies, and sibling Kotlin source-set configuration.
samples/ Sample .adbrush preset files (e.g., Ink_Pen_Texturized.adbrush).

The project intentionally keeps the Kotlin source under the sibling graphicsdrawing/ directory and adds it to the app module through the Gradle sourceSets configuration.

8. Requirements

  • Android Studio with a Java 17-compatible environment.
  • Android SDK Platform 35.
  • Android 8.0 / API 26 or newer.
  • USB-OTG support and a compatible VEIKK VO1060 for tablet testing.
  • Touch drawing works without a graphics tablet.

9. Build and run

From the project root:

./gradlew assembleDebug

Windows PowerShell:

.\gradlew.bat assembleDebug

The debug APK is generated under app/build/outputs/apk/debug/.

For USB-specific changes, install the APK on a physical Android device and test the VO1060 through USB-OTG. Raw capture itself does not require a USB-debugging connection.

10. Documentation layout

Only these project Markdown files are intended to remain as maintained project documentation:

  • README.md — current implemented behavior, current architecture, verified hardware findings, build/use information, and documentation index.
  • FEATURES_TO_IMPLEMENT.md — the single source of truth for planned, incomplete, deliberately deferred, or not-yet-verified features. This replaces the older collection of separate implementation plans/reports.
  • CONTRIBUTING.md — contribution, testing, and review workflow.

The .adbrush format is documented below instead of using a separate ADBRUSH_FORMAT.md file.

11. Features to implement / verify

See FEATURES_TO_IMPLEMENT.md. It is intentionally organized by priority and by verification status so future coding work does not require reading multiple historical Markdown files.

Highest-priority open items currently include:

  1. Verify/calibrate tilt neutral offsets and physical-angle scaling before changing brush behavior.
  2. Capture and decode the dial clockwise/anticlockwise packets; keep dial rotation disabled until verified.
  3. Add a configurable pressure-response curve and, where useful, separate pressure/tilt temporal smoothing without introducing latency.
  4. Implement Advanced (AI) shape recognition only when the desired offline/on-device model behavior is defined and tested.
  5. Continue the longer-term brush/stroke architecture improvements without breaking layers, undo/redo, viewport transforms, touch input, or existing performance work.
  6. Add editable project/document save/load, additional tools/brushes, adaptive layouts/accessibility, and automated tests as separately tracked future work.

12. Custom .adbrush preset format

The app-owned brush preset format is a UTF-8 JSON file with the .adbrush extension. It stores preset metadata/defaults only; rendering remains in the app's native brush engine.

Current format:

{
  "format": "adbrush",
  "version": 1,
  "id": "textured-ink-pen",
  "name": "Textured Ink Pen",
  "engine": "PEN",
  "defaults": {
    "size": 8,
    "opacity": 85,
    "density": 100
  },
  "options": ["size", "opacity"]
}

engine must currently refer to one of the app's built-in brush engine/type values (PEN, INK, CRAYON). The preset format is intentionally separate from the drawing model, so importing/removing a preset does not rewrite the built-in brush implementations.

A sample preset (Ink_Pen_Texturized.adbrush) is included under samples/. It also carries an optional source block documenting its origin from a Krita brush preset; that block is informational and is not used by the rendering engine.

13. Important development rule

Do not perform a large rewrite merely to add one new tablet or drawing feature.

Before changing code:

  1. Understand the current responsibility of the file.
  2. Identify the exact reason the change is needed.
  3. Make the smallest isolated change possible.
  4. Build/test.
  5. Run regression tests for existing drawing, layers, undo/redo, viewport, touch input, and USB input where applicable.
  6. Move to the next stage only after the previous stage is stable.

Unverified hardware behavior must never be presented as confirmed functionality.

14. License

This project is licensed under the terms included in LICENSE.

About

Android drawing app with VEIKK tablet support, pressure-sensitive brushes, layers, and .adbrush presets

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages