Files
god_eye/docs/TECHNICAL_SPECIFICATION_ANDROID.md
2025-10-04 11:55:55 +09:00

480 lines
20 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Техническое задание и промпт для создания Android приложения GodEye Signal Center
## 🎯 ТЕХНИЧЕСКОЕ ЗАДАНИЕ
### Назначение системы
Создать Android приложение для системы удаленного доступа к камерам смартфона "GodEye Signal Center". Приложение должно предоставлять операторам доступ к камерам устройства через WebRTC с возможностью переключения между различными типами камер.
### Архитектура системы
```
[Android App] ←→ [WebSocket/Socket.IO] ←→ [Backend Server] ←→ [Desktop Operator]
←→ [WebRTC P2P Connection] ←→ [Desktop Operator]
```
### Основные компоненты
1. **MainActivity** - главный экран с управлением подключением
2. **SocketService** - сервис для WebSocket соединения с backend
3. **CameraManager** - управление камерами устройства (Camera2 API)
4. **WebRTCManager** - обработка WebRTC соединений для видеопотока
5. **PermissionManager** - управление разрешениями приложения
6. **SessionManager** - управление активными сессиями с операторами
### Функциональные требования
- ✅ Подключение к backend серверу по WebSocket (Socket.IO)
- ✅ Регистрация устройства с передачей характеристик
- ✅ Получение и обработка запросов доступа к камере от операторов
- ✅ Диалоги согласия пользователя на доступ к камере
- ✅ WebRTC соединение для передачи видеопотока
- ✅ Переключение между камерами: основная, фронтальная, широкоугольная, телеобъектив
- ✅ Отображение активных сессий и их управление
- ✅ Автоматическое переподключение при обрыве соединения
- ✅ Работа в фоне (Foreground Service)
- ✅ Уведомления о статусе подключения
### Технические требования
- **Платформа**: Android API 24+ (Android 7.0+)
- **Язык**: Kotlin
- **Архитектура**: MVVM с LiveData
- **Сеть**: Socket.IO для сигнализации, WebRTC для медиа
- **Камера**: Camera2 API для работы с камерами
- **UI**: Material Design 3
- **Разрешения**: CAMERA, RECORD_AUDIO, INTERNET, FOREGROUND_SERVICE
## 📋 ПОЛНЫЙ ПРОМПТ ДЛЯ COPILOT
---
**Создай полное Android приложение на Kotlin для системы GodEye Signal Center со следующими требованиями:**
### 🚀 ОСНОВНАЯ ЗАДАЧА
Разработать Android приложение, которое подключается к backend серверу, получает запросы от операторов на доступ к камере устройства и предоставляет видеопоток через WebRTC с возможностью переключения между камерами.
### 📱 СТРУКТУРА ПРОЕКТА
```
app/
├── src/main/
│ ├── java/com/godeye/android/
│ │ ├── MainActivity.kt
│ │ ├── services/
│ │ │ ├── SocketService.kt
│ │ │ └── CameraService.kt
│ │ ├── managers/
│ │ │ ├── CameraManager.kt
│ │ │ ├── WebRTCManager.kt
│ │ │ ├── SessionManager.kt
│ │ │ └── PermissionManager.kt
│ │ ├── models/
│ │ │ ├── DeviceInfo.kt
│ │ │ ├── CameraSession.kt
│ │ │ └── SocketEvents.kt
│ │ ├── ui/
│ │ │ ├── dialogs/
│ │ │ │ └── CameraRequestDialog.kt
│ │ │ └── adapters/
│ │ │ └── SessionAdapter.kt
│ │ └── utils/
│ │ ├── Constants.kt
│ │ └── Extensions.kt
│ ├── res/
│ │ ├── layout/
│ │ │ ├── activity_main.xml
│ │ │ ├── dialog_camera_request.xml
│ │ │ └── item_session.xml
│ │ ├── values/
│ │ │ ├── strings.xml
│ │ │ ├── colors.xml
│ │ │ └── themes.xml
│ │ └── drawable/
│ └── AndroidManifest.xml
└── build.gradle (app)
```
### 🔧 BACKEND API ENDPOINTS
#### WebSocket События (Socket.IO на порту 3001):
```kotlin
// Регистрация устройства
socket.emit("register:android", JsonObject().apply {
addProperty("deviceId", deviceId)
add("deviceInfo", JsonObject().apply {
addProperty("model", Build.MODEL)
addProperty("androidVersion", Build.VERSION.RELEASE)
addProperty("appVersion", "1.0.0")
add("availableCameras", JsonArray().apply {
add("back"); add("front"); add("wide"); add("telephoto")
})
})
})
// Обработка входящих событий
socket.on("register:success") { /* успешная регистрация */ }
socket.on("camera:request") { /* запрос доступа к камере */ }
socket.on("camera:disconnect") { /* завершение сессии */ }
socket.on("camera:switch") { /* переключение камеры */ }
socket.on("webrtc:offer") { /* WebRTC offer от оператора */ }
socket.on("webrtc:ice-candidate") { /* ICE candidates */ }
// Отправка ответов
socket.emit("camera:response", JsonObject().apply {
addProperty("sessionId", sessionId)
addProperty("accepted", true)
})
socket.emit("webrtc:answer", JsonObject().apply {
addProperty("sessionId", sessionId)
add("answer", /* RTCSessionDescription */)
})
```
### 🎨 UI/UX ТРЕБОВАНИЯ
#### MainActivity.xml:
```xml
<!-- Основной экран с полями: -->
- TextView: Device ID (автогенерируемый)
- EditText: Server URL (по умолчанию: http://192.168.1.100:3001)
- TextView: Connection Status
- Button: Connect/Disconnect
- RecyclerView: Active Sessions
- ProgressBar: Connection progress
- FloatingActionButton: Settings
```
#### CameraRequestDialog.xml:
```xml
<!-- Диалог запроса доступа: -->
- ImageView: Operator avatar/icon
- TextView: "Оператор {operatorId} запрашивает доступ к камере {cameraType}"
- TextView: Session ID
- Button: "Разрешить" / "Отклонить"
- CheckBox: "Запомнить для этого оператора"
```
### 💾 DATA MODELS
```kotlin
data class DeviceInfo(
val model: String,
val androidVersion: String,
val appVersion: String,
val availableCameras: List<String>
)
data class CameraSession(
val sessionId: String,
val operatorId: String,
val cameraType: String,
val startTime: Long,
var isActive: Boolean = true,
var webRTCConnected: Boolean = false
)
sealed class SocketEvent {
data class RegisterAndroid(val deviceId: String, val deviceInfo: DeviceInfo) : SocketEvent()
data class CameraRequest(val sessionId: String, val operatorId: String, val cameraType: String) : SocketEvent()
data class CameraResponse(val sessionId: String, val accepted: Boolean) : SocketEvent()
data class WebRTCOffer(val sessionId: String, val offer: String) : SocketEvent()
data class WebRTCAnswer(val sessionId: String, val answer: String) : SocketEvent()
}
```
### 🔐 РАЗРЕШЕНИЯ (AndroidManifest.xml):
```xml
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.microphone" android:required="true" />
```
### 📚 DEPENDENCIES (build.gradle):
```gradle
dependencies {
implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.7.0'
implementation 'androidx.activity:activity-ktx:1.8.2'
// Socket.IO для WebSocket соединения
implementation 'io.socket:socket.io-client:2.1.0'
// WebRTC для видеопотока
implementation 'org.webrtc:google-webrtc:1.0.32006'
// Camera2 API
implementation 'androidx.camera:camera-core:1.3.1'
implementation 'androidx.camera:camera-camera2:1.3.1'
implementation 'androidx.camera:camera-lifecycle:1.3.1'
implementation 'androidx.camera:camera-view:1.3.1'
// JSON парсинг
implementation 'com.google.code.gson:gson:2.10.1'
// Корутины
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
// RecyclerView
implementation 'androidx.recyclerview:recyclerview:1.3.2'
// Work Manager для фоновых задач
implementation 'androidx.work:work-runtime-ktx:2.9.0'
}
```
### 🏗️ ОСНОВНЫЕ КЛАССЫ
#### 1. MainActivity.kt - Основная логика:
```kotlin
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var socketService: SocketService
private lateinit var sessionAdapter: SessionAdapter
private val viewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
// Инициализация UI
// Проверка разрешений
// Настройка RecyclerView для сессий
// Подключение к SocketService
}
private fun connectToServer() {
val serverUrl = binding.etServerUrl.text.toString()
socketService.connect(serverUrl)
}
private fun showCameraRequestDialog(request: CameraRequest) {
CameraRequestDialog.newInstance(request).show(supportFragmentManager, "camera_request")
}
}
```
#### 2. SocketService.kt - WebSocket соединение:
```kotlin
class SocketService : Service() {
private lateinit var socket: Socket
private val binder = LocalBinder()
fun connect(serverUrl: String) {
socket = IO.socket(serverUrl)
socket.connect()
registerDevice()
setupEventListeners()
}
private fun registerDevice() {
val deviceInfo = DeviceInfo(
model = Build.MODEL,
androidVersion = Build.VERSION.RELEASE,
appVersion = BuildConfig.VERSION_NAME,
availableCameras = CameraManager.getAvailableCameraTypes()
)
socket.emit("register:android", gson.toJson(RegisterAndroid(deviceId, deviceInfo)))
}
private fun setupEventListeners() {
socket.on("camera:request") { args ->
val request = gson.fromJson(args[0].toString(), CameraRequest::class.java)
// Отправить broadcast для показа диалога
}
}
}
```
#### 3. CameraManager.kt - Управление камерами:
```kotlin
class CameraManager(private val context: Context) {
private val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as android.hardware.camera2.CameraManager
private var currentCameraId: String? = null
private var captureSession: CameraCaptureSession? = null
fun getAvailableCameraTypes(): List<String> {
val cameras = mutableListOf<String>()
try {
for (cameraId in cameraManager.cameraIdList) {
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
val facing = characteristics.get(CameraCharacteristics.LENS_FACING)
when (facing) {
CameraCharacteristics.LENS_FACING_BACK -> cameras.add("back")
CameraCharacteristics.LENS_FACING_FRONT -> cameras.add("front")
}
// Проверка на wide и telephoto
}
} catch (e: Exception) {
Log.e("CameraManager", "Error getting cameras", e)
}
return cameras
}
@SuppressLint("MissingPermission")
fun startCamera(cameraType: String, surface: Surface) {
val cameraId = getCameraIdForType(cameraType) ?: return
cameraManager.openCamera(cameraId, cameraStateCallback, null)
}
}
```
#### 4. WebRTCManager.kt - WebRTC соединения:
```kotlin
class WebRTCManager(private val context: Context) {
private lateinit var peerConnectionFactory: PeerConnectionFactory
private var peerConnection: RTCPeerConnection? = null
private var localVideoSource: VideoSource? = null
fun initialize() {
val initializationOptions = PeerConnectionFactory.InitializationOptions.builder(context)
.setEnableInternalTracer(false)
.createInitializationOptions()
PeerConnectionFactory.initialize(initializationOptions)
val options = PeerConnectionFactory.Options()
peerConnectionFactory = PeerConnectionFactory.builder()
.setOptions(options)
.createPeerConnectionFactory()
}
fun createOffer(sessionId: String) {
val mediaConstraints = MediaConstraints()
peerConnection?.createOffer(object : SdpObserver {
override fun onCreateSuccess(sessionDescription: SessionDescription) {
// Отправить offer через WebSocket
}
}, mediaConstraints)
}
fun handleAnswer(sessionId: String, answer: SessionDescription) {
peerConnection?.setRemoteDescription(SimpleSdpObserver(), answer)
}
}
```
### 🔄 WORKFLOW ПРИЛОЖЕНИЯ
1. **Запуск приложения:**
- Проверка разрешений (CAMERA, AUDIO, INTERNET)
- Генерация уникального Device ID
- Определение доступных камер устройства
- Инициализация WebRTC
2. **Подключение к серверу:**
- Подключение Socket.IO к указанному URL
- Регистрация устройства с отправкой характеристик
- Ожидание подтверждения регистрации
- Запуск Foreground Service для фоновой работы
3. **Обработка запроса камеры:**
- Получение события "camera:request" от сервера
- Показ диалога пользователю с информацией об операторе
- При согласии - отправка "camera:response" с accepted: true
- Инициализация WebRTC соединения
4. **WebRTC соединение:**
- Создание RTCPeerConnection
- Настройка локального видеопотока с указанной камеры
- Обмен offer/answer/ice-candidates с оператором
- Начало передачи видеопотока
5. **Управление сессией:**
- Отображение активных сессий в RecyclerView
- Обработка команд переключения камеры
- Завершение сессии по команде оператора или пользователя
- Очистка ресурсов WebRTC
### ⚙️ НАСТРОЙКИ И КОНФИГУРАЦИЯ
#### SharedPreferences ключи:
```kotlin
object PreferenceKeys {
const val SERVER_URL = "server_url"
const val DEVICE_ID = "device_id"
const val AUTO_ACCEPT_REQUESTS = "auto_accept_requests"
const val CAMERA_QUALITY = "camera_quality"
const val NOTIFICATION_ENABLED = "notification_enabled"
}
```
#### Настройки WebRTC:
```kotlin
val iceServers = listOf(
RTCIceServer.builder("stun:stun.l.google.com:19302").build(),
RTCIceServer.builder("stun:stun1.l.google.com:19302").build()
)
val rtcConfig = RTCConfiguration(iceServers).apply {
tcpCandidatePolicy = RTCConfiguration.TcpCandidatePolicy.DISABLED
bundlePolicy = RTCConfiguration.BundlePolicy.MAXBUNDLE
rtcpMuxPolicy = RTCConfiguration.RtcpMuxPolicy.REQUIRE
}
```
### 🐛 ОБРАБОТКА ОШИБОК
```kotlin
sealed class AppError {
object NetworkError : AppError()
object CameraPermissionDenied : AppError()
object CameraNotAvailable : AppError()
object WebRTCConnectionFailed : AppError()
data class SocketError(val message: String) : AppError()
data class UnknownError(val throwable: Throwable) : AppError()
}
class ErrorHandler {
fun handleError(error: AppError, context: Context) {
when (error) {
is AppError.NetworkError -> showNetworkError(context)
is AppError.CameraPermissionDenied -> showPermissionDialog(context)
is AppError.WebRTCConnectionFailed -> restartWebRTC()
// и т.д.
}
}
}
```
### 📋 ТЕСТИРОВАНИЕ
1. **Запуск backend сервера**: `cd backend && node src/server.js`
2. **Веб-демо оператора**: `http://localhost:3001`
3. **Подключение Android**: указать URL `http://192.168.1.100:3001`
4. **Тестовые сценарии**:
- Регистрация устройства
- Запрос доступа к камере от веб-демо
- Переключение между камерами
- Разрыв и восстановление соединения
### 🚀 ФИНАЛЬНЫЕ ТРЕБОВАНИЯ
**Создай полный рабочий проект со всеми перечисленными файлами, который:**
- ✅ Компилируется без ошибок на API 24+
- ✅ Корректно подключается к backend серверу
- ✅ Отображает запросы операторов в диалогах
- ✅ Передает видеопоток через WebRTC
- ✅ Поддерживает переключение камер
- ✅ Работает в фоне с уведомлениями
- ✅ Имеет современный Material Design UI
- ✅ Обрабатывает все ошибки и исключения
**Backend server URL для тестирования**: `http://localhost:3001` или `http://192.168.1.100:3001`
---
### 📝 ДОПОЛНИТЕЛЬНЫЕ ПРИМЕЧАНИЯ
- Используй современный Kotlin синтаксис с корутинами
- Применяй MVVM архитектуру с LiveData/StateFlow
- Все строки выноси в strings.xml с поддержкой русского языка
- Добавь логирование всех важных событий
- Используй Material Design 3 компоненты
- Обеспечь backward compatibility с API 24
- Добавь комментарии к сложной логике WebRTC и Camera2
**Этот промпт содержит все необходимые технические детали для создания полнофункционального Android приложения GodEye Signal Center!**