π± Android App: Clean MVVM Architecture
π Recommended Project Structure
app/
βββ src/main/java/com/airmouse/
β βββ di/ # Dependency Injection (Hilt)
β β βββ AppModule.kt
β β βββ NetworkModule.kt
β β βββ SensorModule.kt
β βββ domain/ # Clean Architecture: Domain Layer
β β βββ model/ # Business models (pure Kotlin)
β β β βββ MouseEvent.kt
β β β βββ Gesture.kt
β β β βββ ConnectionConfig.kt
β β βββ repository/ # Interfaces for data operations
β β β βββ IMouseRepository.kt
β β β βββ IGestureRepository.kt
β β β βββ IConnectionRepository.kt
β β βββ usecase/ # Business logic (interactors)
β β βββ SendMovementUseCase.kt
β β βββ DetectGestureUseCase.kt
β β βββ ConnectToServerUseCase.kt
β βββ data/ # Data Layer
β β βββ repository/ # Implementations of repository interfaces
β β β βββ MouseRepositoryImpl.kt
β β β βββ ConnectionRepositoryImpl.kt
β β βββ datasource/ # Local & remote data sources
β β β βββ local/ # Room database, DataStore
β β β β βββ PreferencesDao.kt
β β β β βββ AppDatabase.kt
β β β βββ remote/ # WebSocket, Bluetooth, USB
β β β βββ WebSocketDataSource.kt
β β β βββ BluetoothDataSource.kt
β β β βββ UsbDataSource.kt
β β βββ model/ # Data models (DTOs)
β β βββ NetworkMessage.kt
β β βββ SensorData.kt
β βββ presentation/ # Presentation Layer
β β βββ ui/ # Jetpack Compose Screens
β β β βββ home/
β β β β βββ HomeScreen.kt
β β β β βββ HomeViewModel.kt
β β β β βββ HomeState.kt
β β β βββ calibration/
β β β β βββ CalibrationScreen.kt
β β β β βββ CalibrationViewModel.kt
β β β β βββ CalibrationState.kt
β β β βββ gesture/
β β β β βββ GestureStudioScreen.kt
β β β β βββ GestureStudioViewModel.kt
β β β β βββ GestureStudioState.kt
β β β βββ settings/
β β β β βββ SettingsScreen.kt
β β β β βββ SettingsViewModel.kt
β β β β βββ SettingsState.kt
β β β βββ components/ # Reusable Compose components
β β β βββ ConnectionCard.kt
β β β βββ SensorDataCard.kt
β β β βββ GestureChart.kt
β β βββ theme/ # Material 3 theming
β β β βββ Color.kt
β β β βββ Theme.kt
β β β βββ Type.kt
β β βββ navigation/ # Compose Navigation
β β βββ NavGraph.kt
β β βββ Destinations.kt
β βββ service/ # Android Services
β β βββ SensorService.kt # Foreground service for sensor collection
β β βββ GestureInferenceService.kt
β β βββ ProximityService.kt
β β βββ VoiceCommandService.kt
β β βββ BluetoothHidService.kt
β βββ utils/ # Utility classes
β β βββ Extensions.kt
β β βββ Constants.kt
β β βββ MathUtils.kt
β βββ AirMouseApplication.kt # Application class
βββ src/main/res/ # Resources (icons, themes, etc.)
π§± Core Principles
Clean Architecture (Onion): The architecture follows concentric layers: UI β Domain β Data. Dependencies point inward, so the Domain layer (containing your business logic) remains independent of frameworks. For an Air Mouse app, this means the core logic for interpreting gestures and sending mouse commands is completely separate from Androidβspecific code.
MVVM with Jetpack Compose: The presentation layer uses
ViewModelto hold UI state (exposed asStateFlow) and handle user events. The View (Compose UI) observes this state viacollectAsState(). This ensures the UI only displays data and sends events, while theViewModelcontains the presentation logic.Repository Pattern: The
repositoryinterfaces in the Domain layer are implemented in the Data layer. This abstracts the source of data (network, Bluetooth, USB, local storage). For example, anIMovementRepositorycan have aWebSocketMovementDataSourceand aBluetoothMovementDataSource, both interchangeable without changing the business logic.Dependency Injection (Hilt): All dependencies (repositories, use cases, data sources, services) are injected via Hilt. This makes the code testable and reduces boilerplate.
Kotlin Flows for Asynchronous Data: Use
StateFlowfor UI state,SharedFlowfor oneβtime events (e.g.,showToast), andFlowfor continuous data streams (sensor data, incoming WebSocket messages). This integrates seamlessly with Compose.
π Communication Protocols (Choice Matrix)
Select the protocol based on your specific requirements (WiβFi reliability, latency tolerance, security needs, etc.):
| Protocol | Overhead | Latency | Pros | Cons | Best for |
|---|---|---|---|---|---|
| WebSocket (TCP) | 2β14 bytes | Low (stable) | Reliable, ordered, firewallβfriendly, simple API | Headβofβline blocking, TCPβs reliability can add jitter | General use on good WiβFi (your primary choice) |
| UDP + custom ACK | 8 bytes | Very low | Lowest latency, no retransmission overhead | Unreliable, packets may arrive out of order | Gaming / ultraβlowβlatency requirements |
| QUIC | Low (similar to TCPβTLS) | Lower than TCP | Combines reliability and low latency, 0βRTT handshake | Emerging, library support varies | Remote connections over the internet |
| USB HID | <10 bytes | Extremely low | Direct cable, no network issues | Wired only, requires OTG adapter | Professional / stationary use |
| Bluetooth (HID/GATT) | 5β10 bytes | Low (5β20 ms) | Wireless, standardised HID profile | Range limited, pairing required | Casual / mobile use |
For most cases, WebSocket over TCP is the best balance of simplicity and performance. If you later need to support weak networks, QUIC is a great upgrade because it avoids headβofβline blocking and allows 0βRTT connection resumption. USB and Bluetooth HID modes are excellent for local, direct connections.
π‘ Message Protocol (Binary for Performance)
Strong recommendation: Use Protocol Buffers (protobuf) or MessagePack instead of JSON. These binary formats are significantly more compact and faster to parse, which is crucial for realβtime applications. Here is a minimal protobuf schema:
syntax = "proto3";
message Movement {
float dx = 1;
float dy = 2;
}
message Click {
string button = 1;
}
message Scroll {
int32 delta = 1;
}
message Command {
oneof command_type {
Movement move = 1;
Click click = 2;
DoubleClick double_click = 3;
Scroll scroll = 4;
Hello hello = 5;
}
}
This reduces packet size by 30β50% compared to JSON, lowering latency and saving battery on the phone.
π Security & Data Persistence
- Authentication: Use a shortβlived JWT token generated by the server and exchanged via a QR code. The token is included in the WebSocket upgrade request (
ws://server:8080/ws?token=...). This prevents unauthorised clients from controlling the mouse. - Encryption: On the local network, you may skip TLS for performance, but for any remote connection you must use WSS (WebSocket over TLS) or QUIC (which has builtβin TLS 1.3).
- Local Storage (Room): Store user preferences (sensitivity, thresholds), saved gestures (as templates), and calibration data in a local Room database.
- DataStore: Use
Preferences DataStorefor simple keyβvalue settings (e.g., last used IP, theme).
π€ Sensor Data Collection & Gesture Recognition
- Foreground Service + SensorManager: Use a foreground service (with a persistent notification) to collect gyroscope and accelerometer data, even when the app is in the background. The service registers listeners with
SensorManagerat the fastest possible rate (SENSOR_DELAY_FASTEST). - Gesture Recognition Pipeline:
- Data Buffer: Maintain a sliding window of the last
Nsensor events (e.g., 50 samples). - Feature Extraction: Compute angular velocity (gyro), linear acceleration, and orientation (using
SensorManager.getRotationMatrixFromVector). - Classification: Feed the features into a TensorFlow Lite model (trained onβdevice) that outputs a gesture label and confidence.
- Postβprocessing: Apply a confidence threshold (β₯0.7) and a cooldown (500 ms) to avoid duplicate triggers.
- Data Buffer: Maintain a sliding window of the last
- Optimisation: To reduce battery drain, lower the sensor sampling rate (
SENSOR_DELAY_UI) when the phone is idle (detected via accelerometer variance).
π‘ Additional Considerations
- Testing: Use the
testsource set with JUnit, MockK, and Robolectric. Mock external dependencies (WebSocket, Bluetooth) to test the use cases in isolation. - Error Handling: Use
Eitheror a sealed class (Result<T>) to represent failures (network errors, sensor unavailable). Propagate these to the UI layer. - MultiβModule Setup: Separate features into independent modules for better build times and team scalability:
:core:domain,:core:data,:feature:home,:feature:calibration, etc.
The Android app is now designed to be scalable, testable, and maintainable while delivering a smooth realβtime mouse control experience.
π₯οΈ Go Server: Clean Architecture with Modular Design
π Recommended Project Structure
airmouse-go/
βββ cmd/
β βββ airmouse-server/
β βββ main.go # Entry point, DI container
βββ internal/
β βββ domain/ # Domain Layer (pure business logic)
β β βββ entity/ # Core business objects
β β β βββ mouse.go
β β β βββ gesture.go
β β β βββ client.go
β β βββ repository/ # Repository interfaces (for data access)
β β β βββ mouse_repository.go
β β β βββ gesture_repository.go
β β β βββ client_repository.go
β β βββ service/ # Business logic / Use Cases
β β βββ mouse_service.go
β β βββ gesture_service.go
β β βββ connection_service.go
β βββ repository/ # Data Layer
β β βββ mouse_repository_impl.go
β β βββ gesture_repository_impl.go
β β βββ client_repository_impl.go
β β βββ config/ # Configuration (JSON, env)
β β βββ config.go
β βββ handler/ # Delivery Layer (HTTP, WebSocket)
β β βββ websocket/
β β β βββ handler.go
β β β βββ client.go
β β β βββ hub.go
β β βββ http/
β β β βββ router.go
β β β βββ middleware.go
β β βββ dto/ # Data Transfer Objects
β β βββ message.go
β β βββ response.go
β βββ infra/ # Infrastructure (external dependencies)
β β βββ mouse/ # Platformβspecific mouse control
β β β βββ mouse.go # Interface
β β β βββ windows.go
β β β βββ darwin.go
β β β βββ linux.go
β β βββ bluetooth/ # BLE, HID
β β β βββ manager.go
β β βββ usb/ # USB gadget mode
β β β βββ gadget.go
β β βββ logger/ # Structured logging
β β βββ logger.go
β βββ pkg/ # Shared utilities
β βββ errors/ # Custom error types
β βββ utils/ # Helper functions
β βββ config/ # Configuration loader
βββ pkg/ # Public packages (if any)
βββ go.mod
βββ go.sum
βββ Makefile
ποΈ Core Principles (Clean Architecture)
- Layered Design: The architecture is divided into
domain(business rules),repository(data access),handler(delivery), andinfra(external dependencies). Dependencies point inward, so thedomainlayer knows nothing about WebSockets, databases, or OSβspecific mouse code. - Dependency Injection: In
main.go, you manually wire all dependencies. Theinfraimplementations are passed to the constructors of the repository and service layers. This makes the code testable (mock implementations can be substituted). - Concurrency: Use goroutines and channels for handling multiple clients. The WebSocket hub pattern (from
gorilla/websocket) is perfect for broadcasting messages to all connected clients. - Configuration: Use a
config.gothat reads from a JSON file and environment variables. All config values are passed to the services at startup.
π§ Communication Protocol Recommendations (Go Server)
The server is designed to support multiple protocols simultaneously, allowing the client to choose the best one. The recommended primary protocol is WebSocket over TCP because of its simplicity and reliability.
| Protocol | Library | Use Case |
|---|---|---|
| WebSocket | github.com/gorilla/websocket |
Primary protocol (WiβFi, internet) |
| QUIC | github.com/quic-go/quic-go |
Upgrade for lowβlatency remote connections |
| UDP | net |
Custom UDP + lightweight ACK |
| TCP | net |
Plain TCP fallback |
| Bluetooth | github.com/go-ble/ble |
BLE GATT service (discovery, not for data) |
| USB | github.com/karalabe/hid |
USB gadget mode (emulate HID device) |
You can implement a Transport interface and register all active transports in a central Hub. Each transport receives incoming messages, decodes them, and forwards them to the appropriate use case (e.g., MouseService.Move). Responses are sent back through the same transport.
π¦ Message Processing Pipeline
- WebSocket Handler: Upgrades HTTP connection, reads messages as binary (protobuf), and passes them to a
MessageProcessor. - MessageProcessor: Decodes the protobuf message and determines the type (move, click, hello). It then invokes the appropriate use case (e.g.,
mouseService.Move). - Use Case (Service): Contains the business logic (e.g., apply sensitivity, filtering, gesture detection). It may call a repository (e.g., to store statistics).
- Repository: Accesses infrastructure (e.g., inβmemory storage for statistics, configuration).
- Response: The use case returns a result, which the
MessageProcessorencodes back to protobuf and sends to the WebSocket client.
π§ Infrastructure Implementations
- Mouse Control: Platformβspecific files (
mouse_windows.go,mouse_darwin.go,mouse_linux.go) implement theMouseinterface using native APIs (Win32 API, CoreGraphics, uinput). - Bluetooth: The
bluetoothpackage implements GATT services for discovery and pairing. It does not stream cursor data (use WebSocket for that). - USB Gadget Mode: The
usbpackage useslinux/configfs(on supported devices) to emulate a USB HID mouse without any client software on the PC. - Logging: Structured logging with
slog(Go 1.21+) or a thirdβparty library likezerolog. Each log entry includes a correlation ID to trace a request across multiple services.
π€ AI and Personalization
- ONNX Runtime: Use
github.com/yalue/onnxruntime_goto load and execute the LSTM model for trajectory prediction. The inference runs in a separate goroutine (using a worker pool). - Data Collector: The
personalizationpackage collects movement samples (position, velocity, timestamp) and stores them in a circular buffer. When enough samples are collected, it triggers a HTTP call to a Python fineβtuning service (running onlocalhost:5001). The updated model is then loaded via ONNX Runtime.
π§ͺ Testing & Observability
- Unit Tests: Write tests for each use case using the
testingpackage and mocks for repositories. - Integration Tests: Test the WebSocket handler with a real client.
- Metrics: Expose Prometheus metrics (requests per second, active connections, latency) on an
/metricsendpoint. - Health Check: Provide a
/healthendpoint that returns200 OKwhen the server is ready.
The Go server is now designed to be modular, highly performant, and horizontally scalable. Each layer is decoupled, allowing you to replace any component (e.g., switch from WebSocket to QUIC) without affecting the business logic. This architecture supports highβconcurrency (thousands of simultaneous clients) while maintaining subβ20ms latency for cursor movement.
π€ Cross-Project Synchronisation
To keep the Android app and Go server in sync, follow these guidelines:
- Shared Protocol Buffer Schema: Maintain a single
airmouse.protofile in a separate repository. Both projects generate code from this file (using the protobuf compiler). This ensures that message structures never become misaligned. - API Versioning: Prefix your WebSocket endpoint with a version, e.g.,
/ws/v1/. This allows you to introduce breaking changes later. - Continuous Integration: Set up a CI pipeline that, on any change to the
.protofile, automatically regenerates the code for both projects and runs the full test suite. - Version Tags: Tag releases with semantic versioning (e.g.,
v1.2.3) and update the Android appβs build script to require a minimum server version.
Xet Storage Details
- Size:
- 18.9 kB
- Xet hash:
- bf912e8367164748ad46007f1b71023b83f55c31a748e0177c46cd08d7bf025c
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.