package com.jovan.assistant.service import android.content.Context import android.content.Intent import com.jovan.assistant.security.SecurityGuard import java.text.DateFormat import java.util.Date data class CommandResult(val reply: String, val stopListening: Boolean = false) object CommandProcessor { /** Phrases that look like tampering; each attempt counts toward a protective block. */ private val restricted = listOf( "uninstall", "factory reset", "reset phone", "disable security", "turn off security", "accessibility settings", "device admin", "disable protection" ) private val aliases = mapOf( "youtube" to "com.google.android.youtube", "you tube" to "com.google.android.youtube", "chrome" to "com.android.chrome", "maps" to "com.google.android.apps.maps", "google maps" to "com.google.android.apps.maps", "gmail" to "com.google.android.gm", "whatsapp" to "com.whatsapp", "play store" to "com.android.vending", "photos" to "com.google.android.apps.photos" ) fun handle(ctx: Context, raw: String): CommandResult { val cmd = raw.lowercase().replace(Regex("[^a-z0-9 ]"), " ").replace(Regex("\\s+"), " ").trim() if (cmd.isBlank()) return CommandResult("I didn't catch that.") if (restricted.any { cmd.contains(it) }) { SecurityGuard.report("Restricted command attempted: \"$cmd\"") return CommandResult("Sorry, I can't do that.") } if (cmd.startsWith("stop listening") || cmd == "goodbye" || cmd == "shut down") { return CommandResult("Okay, going to sleep.", stopListening = true) } if (cmd.contains("what time") || cmd == "time") { return CommandResult("It is " + DateFormat.getTimeInstance(DateFormat.SHORT).format(Date())) } // Everything below needs the accessibility service. val svc = AssistantAccessibilityService.instance ?: return CommandResult("Please enable the accessibility service in settings first.") fun done(ok: Boolean, success: String): CommandResult { if (!ok) SecurityGuard.report("Action failed: \"$cmd\"", SecurityGuard.Severity.ERROR) return CommandResult(if (ok) success else "That action failed.") } return when { cmd.startsWith("open ") || cmd.startsWith("launch ") || cmd.startsWith("start ") -> { val name = cmd.substringAfter(' ').trim() val intent = findLaunchIntent(ctx, name) if (intent == null) { SecurityGuard.report("App not found: \"$name\"", SecurityGuard.Severity.ERROR) CommandResult("I couldn't find $name.") } else done(svc.launch(intent), "Opening $name") } cmd.contains("lock") && (cmd.contains("screen") || cmd.contains("phone") || cmd == "lock") -> done(svc.lockScreen(), "Locking the screen") cmd.contains("go home") || cmd == "home" -> done(svc.goHome(), "Going home") cmd.contains("go back") || cmd == "back" -> done(svc.goBack(), "Going back") cmd.contains("recent") -> done(svc.showRecents(), "Showing recent apps") cmd.contains("notification") -> done(svc.showNotifications(), "Showing notifications") cmd.contains("quick settings") -> done(svc.showQuickSettings(), "Showing quick settings") cmd.contains("screenshot") -> done(svc.screenshot(), "Taking a screenshot") else -> CommandResult("Sorry, I don't know that command.") } } private fun findLaunchIntent(ctx: Context, name: String): Intent? { val pm = ctx.packageManager aliases[name]?.let { pkg -> pm.getLaunchIntentForPackage(pkg)?.let { return it } } val main = Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER) val target = name.replace(" ", "") val apps = pm.queryIntentActivities(main, 0).map { it.loadLabel(pm).toString().lowercase().replace(" ", "") to it.activityInfo.packageName } val pkg = apps.firstOrNull { it.first == target }?.second ?: apps.firstOrNull { target.length >= 3 && it.first.contains(target) }?.second ?: return null return pm.getLaunchIntentForPackage(pkg) } }