|
|
|
|
@ -2,10 +2,13 @@ package com.example.hmg_qline.hmg_qline
|
|
|
|
|
|
|
|
|
|
import android.content.Intent
|
|
|
|
|
import android.os.Bundle
|
|
|
|
|
import android.os.Handler
|
|
|
|
|
import android.os.Looper
|
|
|
|
|
import android.util.Log
|
|
|
|
|
import io.flutter.embedding.android.FlutterActivity
|
|
|
|
|
import io.flutter.embedding.engine.FlutterEngine
|
|
|
|
|
import io.flutter.plugin.common.MethodChannel
|
|
|
|
|
import java.io.File
|
|
|
|
|
|
|
|
|
|
class MainActivity : FlutterActivity() {
|
|
|
|
|
private val CHANNEL = "com.example.hmg_qline/foreground"
|
|
|
|
|
@ -15,17 +18,353 @@ class MainActivity : FlutterActivity() {
|
|
|
|
|
|
|
|
|
|
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
|
|
|
|
|
Log.d("MainActivity", "MethodChannel call received: ${call.method}")
|
|
|
|
|
|
|
|
|
|
when (call.method) {
|
|
|
|
|
"reopenApp" -> {
|
|
|
|
|
Log.d("MainActivity", "reopenApp called, bringing app to foreground")
|
|
|
|
|
// Simply bring current activity to foreground
|
|
|
|
|
moveTaskToBack(false)
|
|
|
|
|
// Or trigger Flutter navigation if needed
|
|
|
|
|
result.success("App brought to foreground")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else -> result.notImplemented()
|
|
|
|
|
"restartApp" -> {
|
|
|
|
|
Log.d("MainActivity", "Restarting application")
|
|
|
|
|
restartApplication()
|
|
|
|
|
result.success("App restart initiated")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"restartDevice" -> {
|
|
|
|
|
Log.d("MainActivity", "Attempting device restart")
|
|
|
|
|
restartDevice(result)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"runShellScript" -> {
|
|
|
|
|
Log.d("MainActivity", "Executing shell restart command")
|
|
|
|
|
executeShellRestart(result)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"clearAudioCache" -> {
|
|
|
|
|
Log.d("MainActivity", "Clearing audio cache")
|
|
|
|
|
clearAudioResources()
|
|
|
|
|
result.success("Audio cache cleared")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"clearAllResources" -> {
|
|
|
|
|
Log.d("MainActivity", "Clearing all native resources")
|
|
|
|
|
clearAllNativeResources()
|
|
|
|
|
result.success("All resources cleared")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else -> {
|
|
|
|
|
Log.w("MainActivity", "Method not implemented: ${call.method}")
|
|
|
|
|
result.notImplemented()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun restartApplication() {
|
|
|
|
|
try {
|
|
|
|
|
Log.d("MainActivity", "Initiating app restart")
|
|
|
|
|
|
|
|
|
|
// Clear resources before restart
|
|
|
|
|
clearAllNativeResources()
|
|
|
|
|
|
|
|
|
|
// Create restart intent
|
|
|
|
|
val intent = packageManager.getLaunchIntentForPackage(packageName)?.apply {
|
|
|
|
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
|
|
|
|
putExtra("restarted", true)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (intent != null) {
|
|
|
|
|
// Use a shorter delay for faster restart
|
|
|
|
|
Handler(Looper.getMainLooper()).postDelayed({
|
|
|
|
|
startActivity(intent)
|
|
|
|
|
finishAffinity()
|
|
|
|
|
// Remove exitProcess() call if present
|
|
|
|
|
// android.os.Process.killProcess(android.os.Process.myPid())
|
|
|
|
|
}, 100) // Reduced delay
|
|
|
|
|
|
|
|
|
|
Log.d("MainActivity", "App restart initiated")
|
|
|
|
|
} else {
|
|
|
|
|
Log.e("MainActivity", "Could not create restart intent")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (e: Exception) {
|
|
|
|
|
Log.e("MainActivity", "Error during restart: ${e.message}")
|
|
|
|
|
// Fallback - don't exit, just log the error
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun restartDevice(result: MethodChannel.Result) {
|
|
|
|
|
try {
|
|
|
|
|
Log.d("MainActivity", "Attempting device restart (requires root)")
|
|
|
|
|
|
|
|
|
|
// Try different reboot commands
|
|
|
|
|
val rebootCommands = arrayOf(
|
|
|
|
|
arrayOf("su", "-c", "reboot"),
|
|
|
|
|
arrayOf("su", "-c", "reboot now"),
|
|
|
|
|
arrayOf("reboot")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var success = false
|
|
|
|
|
for (command in rebootCommands) {
|
|
|
|
|
try {
|
|
|
|
|
val process = Runtime.getRuntime().exec(command)
|
|
|
|
|
val exitCode = process.waitFor()
|
|
|
|
|
|
|
|
|
|
if (exitCode == 0) {
|
|
|
|
|
success = true
|
|
|
|
|
Log.d("MainActivity", "Device restart command executed successfully")
|
|
|
|
|
result.success("Device restart initiated")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
} catch (e: Exception) {
|
|
|
|
|
Log.w("MainActivity", "Reboot command failed: ${command.joinToString(" ")}")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!success) {
|
|
|
|
|
Log.e("MainActivity", "All reboot commands failed - device may not have root access")
|
|
|
|
|
result.error("RESTART_ERROR", "Device restart failed - root access required", null)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (e: Exception) {
|
|
|
|
|
Log.e("MainActivity", "Exception during device restart: ${e.message}")
|
|
|
|
|
result.error("RESTART_ERROR", "Device restart failed: ${e.message}", null)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun executeShellRestart(result: MethodChannel.Result) {
|
|
|
|
|
try {
|
|
|
|
|
Log.d("MainActivity", "Executing shell restart script")
|
|
|
|
|
|
|
|
|
|
// Copy script from assets to internal storage
|
|
|
|
|
val scriptFile = copyAssetToFile("scripts/restart_app.sh")
|
|
|
|
|
|
|
|
|
|
if (scriptFile != null && scriptFile.exists()) {
|
|
|
|
|
// Make script executable
|
|
|
|
|
Runtime.getRuntime().exec("chmod 755 ${scriptFile.absolutePath}")
|
|
|
|
|
|
|
|
|
|
// Execute the script
|
|
|
|
|
val process = Runtime.getRuntime().exec("su -c ${scriptFile.absolutePath}")
|
|
|
|
|
val exitCode = process.waitFor()
|
|
|
|
|
|
|
|
|
|
if (exitCode == 0) {
|
|
|
|
|
result.success("Shell restart executed successfully")
|
|
|
|
|
} else {
|
|
|
|
|
result.error("SHELL_ERROR", "Script execution failed with code: $exitCode", null)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
result.error("SCRIPT_ERROR", "Could not copy script from assets", null)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (e: Exception) {
|
|
|
|
|
Log.e("MainActivity", "Shell restart error: ${e.message}")
|
|
|
|
|
result.error("SHELL_EXCEPTION", e.message, null)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun copyAssetToFile(assetPath: String): File? {
|
|
|
|
|
return try {
|
|
|
|
|
val inputStream = assets.open(assetPath)
|
|
|
|
|
val file = File(filesDir, "restart_app.sh")
|
|
|
|
|
|
|
|
|
|
file.outputStream().use { output ->
|
|
|
|
|
inputStream.copyTo(output)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
file
|
|
|
|
|
} catch (e: Exception) {
|
|
|
|
|
Log.e("MainActivity", "Error copying asset: ${e.message}")
|
|
|
|
|
null
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private fun clearAudioResources() {
|
|
|
|
|
try {
|
|
|
|
|
Log.d("MainActivity", "Clearing audio resources")
|
|
|
|
|
|
|
|
|
|
// Force garbage collection
|
|
|
|
|
System.gc()
|
|
|
|
|
|
|
|
|
|
// Clear audio-related system caches
|
|
|
|
|
val commands = arrayOf(
|
|
|
|
|
"am force-stop com.google.android.tts",
|
|
|
|
|
"am force-stop com.android.providers.media"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
for (command in commands) {
|
|
|
|
|
try {
|
|
|
|
|
Runtime.getRuntime().exec(command)
|
|
|
|
|
} catch (e: Exception) {
|
|
|
|
|
Log.w("MainActivity", "Failed to clear audio service: $command")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (e: Exception) {
|
|
|
|
|
Log.e("MainActivity", "Error clearing audio resources: ${e.message}")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun clearAllNativeResources() {
|
|
|
|
|
try {
|
|
|
|
|
Log.d("MainActivity", "Clearing all native resources")
|
|
|
|
|
|
|
|
|
|
// Clear audio resources
|
|
|
|
|
clearAudioResources()
|
|
|
|
|
|
|
|
|
|
// Clear image caches
|
|
|
|
|
try {
|
|
|
|
|
Runtime.getRuntime().exec("am broadcast -a android.intent.action.MEDIA_MOUNTED")
|
|
|
|
|
} catch (e: Exception) {
|
|
|
|
|
Log.w("MainActivity", "Failed to clear media cache")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Force garbage collection
|
|
|
|
|
System.gc()
|
|
|
|
|
System.runFinalization()
|
|
|
|
|
|
|
|
|
|
Log.d("MainActivity", "Native resources cleared")
|
|
|
|
|
|
|
|
|
|
} catch (e: Exception) {
|
|
|
|
|
Log.e("MainActivity", "Error clearing native resources: ${e.message}")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
|
|
super.onCreate(savedInstanceState)
|
|
|
|
|
|
|
|
|
|
// Log if app was restarted
|
|
|
|
|
if (intent.getBooleanExtra("restarted", false)) {
|
|
|
|
|
Log.d("MainActivity", "App restarted successfully")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Log if launched from boot
|
|
|
|
|
if (intent.getBooleanExtra("launched_from_boot", false)) {
|
|
|
|
|
Log.d("MainActivity", "App launched from boot")
|
|
|
|
|
// Give system time to settle after boot
|
|
|
|
|
Thread.sleep(2000)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onResume() {
|
|
|
|
|
super.onResume()
|
|
|
|
|
Log.d("MainActivity", "Activity resumed")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onPause() {
|
|
|
|
|
super.onPause()
|
|
|
|
|
Log.d("MainActivity", "Activity paused - cleaning up resources")
|
|
|
|
|
|
|
|
|
|
// Light cleanup when app goes to background
|
|
|
|
|
System.gc()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onDestroy() {
|
|
|
|
|
super.onDestroy()
|
|
|
|
|
Log.d("MainActivity", "Activity destroyed")
|
|
|
|
|
|
|
|
|
|
// Final cleanup
|
|
|
|
|
clearAllNativeResources()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//package com.example.hmg_qline.hmg_qline
|
|
|
|
|
//
|
|
|
|
|
//import android.content.Intent
|
|
|
|
|
//import android.os.Bundle
|
|
|
|
|
//import android.util.Log
|
|
|
|
|
//import io.flutter.embedding.android.FlutterActivity
|
|
|
|
|
//import io.flutter.embedding.engine.FlutterEngine
|
|
|
|
|
//import io.flutter.plugin.common.MethodChannel
|
|
|
|
|
//
|
|
|
|
|
//class MainActivity : FlutterActivity() {
|
|
|
|
|
// private val CHANNEL = "com.example.hmg_qline/foreground"
|
|
|
|
|
//
|
|
|
|
|
// override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
|
|
|
|
// super.configureFlutterEngine(flutterEngine)
|
|
|
|
|
//
|
|
|
|
|
// MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
|
|
|
|
|
// Log.d("MainActivity", "MethodChannel call received: ${call.method}")
|
|
|
|
|
// when (call.method) {
|
|
|
|
|
// "reopenApp" -> {
|
|
|
|
|
// Log.d("MainActivity", "reopenApp called, bringing app to foreground")
|
|
|
|
|
// // Simply bring current activity to foreground
|
|
|
|
|
// moveTaskToBack(false)
|
|
|
|
|
// // Or trigger Flutter navigation if needed
|
|
|
|
|
// result.success("App brought to foreground")
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// else -> result.notImplemented()
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// when (call.method) {
|
|
|
|
|
// "runShellScript" -> {
|
|
|
|
|
// Log.d("MainActivity", "reopenApp called, bringing app to foreground")
|
|
|
|
|
// // Simply bring current activity to foreground
|
|
|
|
|
// moveTaskToBack(false)
|
|
|
|
|
// // Or trigger Flutter navigation if needed
|
|
|
|
|
// result.success("App brought to foreground")
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// else -> result.notImplemented()
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//}
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
////}
|
|
|
|
|
////
|
|
|
|
|
//// private fun hasShellPermissions(): Boolean {
|
|
|
|
|
//// return try {
|
|
|
|
|
//// val process = Runtime.getRuntime().exec("id")
|
|
|
|
|
//// process.waitFor()
|
|
|
|
|
//// val exitCode = process.exitValue()
|
|
|
|
|
//// Log.d("MainActivity", "Shell permission check exit code: $exitCode")
|
|
|
|
|
//// exitCode == 0
|
|
|
|
|
//// } catch (e: Exception) {
|
|
|
|
|
//// Log.e("MainActivity", "Error checking shell permissions: ${e.message}")
|
|
|
|
|
//// false
|
|
|
|
|
//// }
|
|
|
|
|
//// }
|
|
|
|
|
////
|
|
|
|
|
//// private fun executeShellScript(result: MethodChannel.Result) {
|
|
|
|
|
//// try {
|
|
|
|
|
//// // Copy script from assets to internal storage
|
|
|
|
|
//// val assetManager = assets
|
|
|
|
|
//// val inputStream = assetManager.open("restart_app.sh")
|
|
|
|
|
//// val scriptFile = java.io.File(filesDir, "restart_app.sh")
|
|
|
|
|
////
|
|
|
|
|
//// scriptFile.outputStream().use { output ->
|
|
|
|
|
//// inputStream.copyTo(output)
|
|
|
|
|
//// }
|
|
|
|
|
////
|
|
|
|
|
//// // Make script executable
|
|
|
|
|
//// scriptFile.setExecutable(true)
|
|
|
|
|
////
|
|
|
|
|
//// // Execute the script
|
|
|
|
|
//// val process = Runtime.getRuntime().exec("sh ${scriptFile.absolutePath}")
|
|
|
|
|
//// val exitCode = process.waitFor()
|
|
|
|
|
////
|
|
|
|
|
//// if (exitCode == 0) {
|
|
|
|
|
//// Log.d("MainActivity", "Shell script executed successfully")
|
|
|
|
|
//// result.success("Script executed successfully")
|
|
|
|
|
//// } else {
|
|
|
|
|
//// val errorStream = process.errorStream.bufferedReader().readText()
|
|
|
|
|
//// Log.e("MainActivity", "Script execution failed with exit code: $exitCode, error: $errorStream")
|
|
|
|
|
//// result.error("SCRIPT_ERROR", "Script execution failed", errorStream)
|
|
|
|
|
//// }
|
|
|
|
|
////
|
|
|
|
|
//// } catch (e: Exception) {
|
|
|
|
|
//// Log.e("MainActivity", "Error executing shell script: ${e.message}")
|
|
|
|
|
//// result.error("EXECUTION_ERROR", "Failed to execute script: ${e.message}", null)
|
|
|
|
|
//// }
|
|
|
|
|
//// }
|
|
|
|
|
|