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.
 
 
 
 
 
 

294 lines
11 KiB

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 com.quillstudios.pokegoalshelper.utils.PGHLog
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 // Using MLInferenceEngine now
// private var yoloDetector_tflite: YOLOTFLiteDetector? = null // Removed - using MLInferenceEngine now
private lateinit var mediaProjectionManager: MediaProjectionManager
private val screenCapturePermissionLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
PGHLog.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
isCapturing = true
PGHLog.d(TAG, "Screen capture service started successfully")
} catch (e: Exception) {
PGHLog.e(TAG, "Failed to start screen capture service", e)
isCapturing = false
}
} else {
PGHLog.e(TAG, "Screen capture permission granted but no data received")
}
} else {
PGHLog.e(TAG, "Screen capture permission denied with result code: ${result.resultCode}")
}
}
private fun initializeOpenCV() {
if (OpenCVLoader.initLocal()) {
PGHLog.d(TAG, "OpenCV loaded successfully")
// Test OpenCV
val testMat = Mat(100, 100, CvType.CV_8UC3)
PGHLog.d(TAG, "Mat created: ${testMat.rows()}x${testMat.cols()}")
// Initialize ONNX YOLO detector for testing - now using MLInferenceEngine in service
// yoloDetector = YOLOOnnxDetector(this)
// if (yoloDetector!!.initialize()) {
// PGHLog.d(TAG, "✅ ONNX YOLO detector initialized successfully")
// } else {
// PGHLog.e(TAG, "❌ ONNX YOLO detector initialization failed")
// }
PGHLog.d(TAG, "✅ Using new MLInferenceEngine architecture in ScreenCaptureService")
} else {
PGHLog.e(TAG, "OpenCV initialization failed")
}
}
private fun testYOLODetection() {
PGHLog.i(TAG, "🧪 YOLO testing now handled by MLInferenceEngine in ScreenCaptureService")
// yoloDetector?.testWithStaticImage()
}
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) {
PGHLog.d(TAG, "Notification permission granted, checking overlay permission")
requestScreenCapturePermission() // Re-check other permissions
} else {
PGHLog.e(TAG, "Notification permission denied")
}
}
private val overlayPermissionLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { _ ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Settings.canDrawOverlays(this)) {
PGHLog.d(TAG, "Overlay permission granted, proceeding with screen capture")
proceedWithScreenCapture()
} else {
PGHLog.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 = {}
)
}
}