| ## π± 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 | |
| 1. **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. | |
| 2. **MVVM with Jetpack Compose**: The presentation layer uses `ViewModel` to hold UI state (exposed as `StateFlow`) and handle user events. The View (Compose UI) observes this state via `collectAsState()`. This ensures the UI only displays data and sends events, while the `ViewModel` contains the presentation logic. | |
| 3. **Repository Pattern**: The `repository` interfaces in the Domain layer are implemented in the Data layer. This abstracts the source of data (network, Bluetooth, USB, local storage). For example, an `IMovementRepository` can have a `WebSocketMovementDataSource` and a `BluetoothMovementDataSource`, both interchangeable without changing the business logic. | |
| 4. **Dependency Injection (Hilt)**: All dependencies (repositories, use cases, data sources, services) are injected via Hilt. This makes the code testable and reduces boilerplate. | |
| 5. **Kotlin Flows for Asynchronous Data**: Use `StateFlow` for UI state, `SharedFlow` for oneβtime events (e.g., `showToast`), and `Flow` for 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: | |
| ```protobuf | |
| 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 DataStore` for 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 `SensorManager` at the fastest possible rate (`SENSOR_DELAY_FASTEST`). | |
| * **Gesture Recognition Pipeline**: | |
| 1. **Data Buffer**: Maintain a sliding window of the last `N` sensor events (e.g., 50 samples). | |
| 2. **Feature Extraction**: Compute angular velocity (gyro), linear acceleration, and orientation (using `SensorManager.getRotationMatrixFromVector`). | |
| 3. **Classification**: Feed the features into a TensorFlow Lite model (trained onβdevice) that outputs a gesture label and confidence. | |
| 4. **Postβprocessing**: Apply a confidence threshold (β₯0.7) and a cooldown (500 ms) to avoid duplicate triggers. | |
| * **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 `test` source set with JUnit, MockK, and Robolectric. Mock external dependencies (WebSocket, Bluetooth) to test the use cases in isolation. | |
| * **Error Handling**: Use `Either` or 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), and `infra` (external dependencies). Dependencies point inward, so the `domain` layer knows nothing about WebSockets, databases, or OSβspecific mouse code. | |
| * **Dependency Injection**: In `main.go`, you manually wire all dependencies. The `infra` implementations 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.go` that 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 | |
| 1. **WebSocket Handler**: Upgrades HTTP connection, reads messages as binary (protobuf), and passes them to a `MessageProcessor`. | |
| 2. **MessageProcessor**: Decodes the protobuf message and determines the type (move, click, hello). It then invokes the appropriate use case (e.g., `mouseService.Move`). | |
| 3. **Use Case (Service)**: Contains the business logic (e.g., apply sensitivity, filtering, gesture detection). It may call a repository (e.g., to store statistics). | |
| 4. **Repository**: Accesses infrastructure (e.g., inβmemory storage for statistics, configuration). | |
| 5. **Response**: The use case returns a result, which the `MessageProcessor` encodes 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 the `Mouse` interface using native APIs (Win32 API, CoreGraphics, uinput). | |
| * **Bluetooth**: The `bluetooth` package implements GATT services for discovery and pairing. It does not stream cursor data (use WebSocket for that). | |
| * **USB Gadget Mode**: The `usb` package uses `linux/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 like `zerolog`. Each log entry includes a correlation ID to trace a request across multiple services. | |
| ### π€ AI and Personalization | |
| * **ONNX Runtime**: Use `github.com/yalue/onnxruntime_go` to load and execute the LSTM model for trajectory prediction. The inference runs in a separate goroutine (using a worker pool). | |
| * **Data Collector**: The `personalization` package 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 on `localhost:5001`). The updated model is then loaded via ONNX Runtime. | |
| ### π§ͺ Testing & Observability | |
| * **Unit Tests**: Write tests for each use case using the `testing` package 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 `/metrics` endpoint. | |
| * **Health Check**: Provide a `/health` endpoint that returns `200 OK` when 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.proto` file 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 `.proto` file, 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.