package com.remotedisplay.player import android.Manifest import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.ServiceConnection import android.content.pm.PackageManager import android.os.Build import android.os.Bundle import android.os.IBinder import android.util.Log import android.view.View import android.view.WindowManager import android.widget.Button import android.widget.EditText import android.widget.ProgressBar import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import com.remotedisplay.player.data.ServerConfig import com.remotedisplay.player.service.WebSocketService class ProvisioningActivity : AppCompatActivity() { private lateinit var config: ServerConfig private var wsService: WebSocketService? = null private var bound = false private lateinit var serverUrlInput: EditText private lateinit var connectBtn: Button private lateinit var pairingCodeText: TextView private lateinit var statusText: TextView private lateinit var progressBar: ProgressBar private lateinit var pairingSection: View private lateinit var serverSection: View private val connection = object : ServiceConnection { override fun onServiceConnected(name: ComponentName?, service: IBinder?) { val binder = service as WebSocketService.LocalBinder wsService = binder.getService() bound = true setupServiceCallbacks() } override fun onServiceDisconnected(name: ComponentName?) { wsService = null bound = false } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_provisioning) // Fullscreen immersive @Suppress("DEPRECATION") window.decorView.systemUiVisibility = ( View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN ) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) config = ServerConfig(this) serverUrlInput = findViewById(R.id.serverUrlInput) connectBtn = findViewById(R.id.connectBtn) pairingCodeText = findViewById(R.id.pairingCodeText) statusText = findViewById(R.id.statusText) progressBar = findViewById(R.id.progressBar) pairingSection = findViewById(R.id.pairingSection) serverSection = findViewById(R.id.serverSection) // Pre-fill if previously entered if (config.serverUrl.isNotEmpty()) { serverUrlInput.setText(config.serverUrl) } connectBtn.setOnClickListener { val url = serverUrlInput.text.toString().trim().trimEnd('/') if (url.isEmpty()) { statusText.text = "Please enter the server URL" return@setOnClickListener } config.serverUrl = url connectToServer(url) } // Request notification permission on Android 13+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.POST_NOTIFICATIONS), 100) } else { startWebSocketService() } } else { startWebSocketService() } } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) // Start service regardless of permission result - it just won't show notification on 13+ startWebSocketService() } private fun startWebSocketService() { try { val serviceIntent = Intent(this, WebSocketService::class.java) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(serviceIntent) } else { startService(serviceIntent) } bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE) } catch (e: Exception) { Log.e("ProvisioningActivity", "Failed to start service: ${e.message}") statusText.text = "Service error: ${e.message}" } } private fun connectToServer(url: String) { connectBtn.isEnabled = false progressBar.visibility = View.VISIBLE statusText.text = "Connecting to server..." wsService?.connect(url) } private fun setupServiceCallbacks() { wsService?.onRegistered = { deviceId -> runOnUiThread { progressBar.visibility = View.GONE // Hide the server/connect controls so the pairing code has the // whole screen and stays visible on short/landscape phones. serverSection.visibility = View.GONE connectBtn.visibility = View.GONE pairingSection.visibility = View.VISIBLE pairingCodeText.text = wsService?.getPairingCode() ?: "------" // The instruction is shown once, inside the pairing section; don't // duplicate it in statusText. statusText.text = "" connectBtn.isEnabled = false } } wsService?.onPaired = { deviceId, name -> runOnUiThread { statusText.text = "Paired as: $name" // Transition to main activity val intent = Intent(this, MainActivity::class.java) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK) startActivity(intent) finish() } } } override fun onDestroy() { if (bound) { unbindService(connection) bound = false } super.onDestroy() } }