You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

293 lines
10 KiB

5 months ago
package com.quillstudios.pokegoalshelper
import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.media.projection.MediaProjectionManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.util.Log
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.quillstudios.pokegoalshelper.ui.theme.PokeGoalsHelperTheme
import org.opencv.android.OpenCVLoader
import org.opencv.core.Mat
import org.opencv.core.CvType
class MainActivity : ComponentActivity() {
companion object {
private const val TAG = "MainActivity"
}
private var isCapturing by mutableStateOf(false)
private var yoloDetector: YOLOOnnxDetector? = null
private var yoloDetector_tflite: YOLOTFLiteDetector? = null
private lateinit var mediaProjectionManager: MediaProjectionManager
private val screenCapturePermissionLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
Log.d(TAG, "Screen capture permission result: ${result.resultCode}")
if (result.resultCode == Activity.RESULT_OK) {
val data = result.data
if (data != null) {
try {
startScreenCaptureService(data)
// FloatingUI now handled by service overlay
5 months ago
isCapturing = true
Log.d(TAG, "Screen capture service started successfully")
} catch (e: Exception) {
Log.e(TAG, "Failed to start screen capture service", e)
isCapturing = false
}
} else {
Log.e(TAG, "Screen capture permission granted but no data received")
}
} else {
Log.e(TAG, "Screen capture permission denied with result code: ${result.resultCode}")
}
}
private fun initializeOpenCV() {
if (OpenCVLoader.initLocal()) {
Log.d(TAG, "OpenCV loaded successfully")
// Test OpenCV
val testMat = Mat(100, 100, CvType.CV_8UC3)
Log.d(TAG, "Mat created: ${testMat.rows()}x${testMat.cols()}")
// Initialize ONNX YOLO detector for testing
5 months ago
yoloDetector = YOLOOnnxDetector(this)
//yoloDetector_tflite = YOLOTFLiteDetector(this)
if (yoloDetector!!.initialize()) {
5 months ago
Log.d(TAG, "✅ ONNX YOLO detector initialized successfully")
} else {
Log.e(TAG, "❌ ONNX YOLO detector initialization failed")
}
} else {
Log.e(TAG, "OpenCV initialization failed")
}
}
private fun testYOLODetection() {
Log.i(TAG, "🧪 Starting ONNX YOLO test with static image...")
5 months ago
yoloDetector?.testWithStaticImage()
5 months ago
}
private fun requestScreenCapturePermission() {
// Check notification permission first (Android 13+)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
notificationPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
return
}
}
// Check overlay permission
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
requestOverlayPermission()
return
}
}
proceedWithScreenCapture()
}
private fun proceedWithScreenCapture() {
mediaProjectionManager = getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
val captureIntent = mediaProjectionManager.createScreenCaptureIntent()
screenCapturePermissionLauncher.launch(captureIntent)
}
private val notificationPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
Log.d(TAG, "Notification permission granted, checking overlay permission")
requestScreenCapturePermission() // Re-check other permissions
} else {
Log.e(TAG, "Notification permission denied")
}
}
private val overlayPermissionLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { _ ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Settings.canDrawOverlays(this)) {
Log.d(TAG, "Overlay permission granted, proceeding with screen capture")
proceedWithScreenCapture()
} else {
Log.e(TAG, "Overlay permission denied")
}
}
}
private fun requestOverlayPermission() {
val intent = Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:$packageName")
)
overlayPermissionLauncher.launch(intent)
}
private fun startScreenCaptureService(data: Intent) {
val serviceIntent = Intent(this, ScreenCaptureService::class.java).apply {
action = ScreenCaptureService.ACTION_START
putExtra(ScreenCaptureService.EXTRA_RESULT_DATA, data)
}
startForegroundService(serviceIntent)
}
private fun stopScreenCaptureService() {
val serviceIntent = Intent(this, ScreenCaptureService::class.java).apply {
action = ScreenCaptureService.ACTION_STOP
}
startService(serviceIntent)
isCapturing = false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
PokeGoalsHelperTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
ScreenCaptureUI(
isCapturing = isCapturing,
onStartCapture = { requestScreenCapturePermission() },
onStopCapture = { stopScreenCaptureService() },
onTestYOLO = { testYOLODetection() },
modifier = Modifier.padding(innerPadding)
)
}
}
}
}
override fun onResume() {
super.onResume()
initializeOpenCV()
}
}
@Composable
fun ScreenCaptureUI(
isCapturing: Boolean,
onStartCapture: () -> Unit,
onStopCapture: () -> Unit,
onTestYOLO: () -> Unit,
modifier: Modifier = Modifier
) {
Column(
modifier = modifier
.fillMaxSize()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Card(
modifier = Modifier.fillMaxWidth(),
elevation = CardDefaults.cardElevation(defaultElevation = 8.dp)
) {
Column(
modifier = Modifier.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Pokemon Home Analysis",
style = MaterialTheme.typography.headlineMedium,
modifier = Modifier.padding(bottom = 16.dp)
)
Text(
text = if (isCapturing) {
"Actively monitoring screen for Pokemon data"
} else {
"Ready to analyze Pokemon Home screens"
},
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(bottom = 24.dp)
)
if (isCapturing) {
Button(
onClick = onStopCapture,
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.error
),
modifier = Modifier.fillMaxWidth()
) {
Text("Stop Analysis")
}
} else {
Button(
onClick = onStartCapture,
modifier = Modifier.fillMaxWidth()
) {
Text("Start Pokemon Analysis")
}
}
if (isCapturing) {
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "📱 Minimize this app and open Pokemon Home",
style = MaterialTheme.typography.bodySmall
)
}
Spacer(modifier = Modifier.height(16.dp))
Button(
onClick = onTestYOLO,
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.secondary
),
modifier = Modifier.fillMaxWidth()
) {
Text("🧪 Test YOLO Detection")
}
}
}
Spacer(modifier = Modifier.height(32.dp))
Text(
text = "Note: This app will request screen capture permission. A notification will show while analysis is active.",
style = MaterialTheme.typography.bodySmall,
modifier = Modifier.padding(horizontal = 16.dp)
)
}
}
@Preview(showBackground = true)
@Composable
fun ScreenCaptureUIPreview() {
PokeGoalsHelperTheme {
ScreenCaptureUI(
isCapturing = false,
onStartCapture = {},
onStopCapture = {},
onTestYOLO = {}
)
}
}