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
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 = {}
|
|
)
|
|
}
|
|
}
|