tahamajs's picture
|
download
raw
18.9 kB
## πŸ“± 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.