main funcions fixes
This commit is contained in:
479
TECHNICAL_SPECIFICATION_ANDROID.md
Normal file
479
TECHNICAL_SPECIFICATION_ANDROID.md
Normal file
@@ -0,0 +1,479 @@
|
||||
# Техническое задание и промпт для создания 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!**
|
||||
Reference in New Issue
Block a user