|
|
|
@ -1,5 +1,8 @@
|
|
|
|
package com.example.hmg_qline.hmg_qline
|
|
|
|
package com.example.hmg_qline.hmg_qline
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import android.app.AlarmManager
|
|
|
|
|
|
|
|
import android.app.PendingIntent
|
|
|
|
|
|
|
|
import android.content.Context
|
|
|
|
import android.content.Intent
|
|
|
|
import android.content.Intent
|
|
|
|
import android.os.Bundle
|
|
|
|
import android.os.Bundle
|
|
|
|
import android.os.Handler
|
|
|
|
import android.os.Handler
|
|
|
|
@ -13,85 +16,168 @@ import java.io.File
|
|
|
|
class MainActivity : FlutterActivity() {
|
|
|
|
class MainActivity : FlutterActivity() {
|
|
|
|
private val CHANNEL = "com.example.hmg_qline/foreground"
|
|
|
|
private val CHANNEL = "com.example.hmg_qline/foreground"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
|
|
|
|
private const val TAG = "MainActivity"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
|
|
|
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
|
|
|
super.configureFlutterEngine(flutterEngine)
|
|
|
|
super.configureFlutterEngine(flutterEngine)
|
|
|
|
|
|
|
|
|
|
|
|
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
|
|
|
|
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
|
|
|
|
Log.d("MainActivity", "MethodChannel call received: ${call.method}")
|
|
|
|
Log.d(TAG, "MethodChannel call received: ${call.method}")
|
|
|
|
|
|
|
|
|
|
|
|
when (call.method) {
|
|
|
|
when (call.method) {
|
|
|
|
"reopenApp" -> {
|
|
|
|
"reopenApp" -> {
|
|
|
|
Log.d("MainActivity", "reopenApp called, bringing app to foreground")
|
|
|
|
Log.d(TAG, "reopenApp called, bringing app to foreground")
|
|
|
|
moveTaskToBack(false)
|
|
|
|
moveTaskToBack(false)
|
|
|
|
result.success("App brought to foreground")
|
|
|
|
result.success("App brought to foreground")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
"restartApp" -> {
|
|
|
|
"restartApp" -> {
|
|
|
|
Log.d("MainActivity", "Restarting application")
|
|
|
|
Log.d(TAG, "Restarting application")
|
|
|
|
restartApplication()
|
|
|
|
restartApplication()
|
|
|
|
result.success("App restart initiated")
|
|
|
|
result.success("App restart initiated")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
"restartDevice" -> {
|
|
|
|
"restartDevice" -> {
|
|
|
|
Log.d("MainActivity", "Attempting device restart")
|
|
|
|
Log.d(TAG, "Attempting device restart")
|
|
|
|
restartDevice(result)
|
|
|
|
restartDevice(result)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
"runShellScript" -> {
|
|
|
|
"runShellScript" -> {
|
|
|
|
Log.d("MainActivity", "Executing shell restart command")
|
|
|
|
Log.d(TAG, "Executing shell restart command")
|
|
|
|
executeShellRestart(result)
|
|
|
|
executeShellRestart(result)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
"clearAudioCache" -> {
|
|
|
|
"clearAudioCache" -> {
|
|
|
|
Log.d("MainActivity", "Clearing audio cache")
|
|
|
|
Log.d(TAG, "Clearing audio cache")
|
|
|
|
clearAudioResources()
|
|
|
|
clearAudioResources()
|
|
|
|
result.success("Audio cache cleared")
|
|
|
|
result.success("Audio cache cleared")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
"clearAllResources" -> {
|
|
|
|
"clearAllResources" -> {
|
|
|
|
Log.d("MainActivity", "Clearing all native resources")
|
|
|
|
Log.d(TAG, "Clearing all native resources")
|
|
|
|
clearAllNativeResources()
|
|
|
|
clearAllNativeResources()
|
|
|
|
result.success("All resources cleared")
|
|
|
|
result.success("All resources cleared")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// === NEW: Alarm Scheduling Methods for Android 14+ compatibility ===
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"scheduleRestartAlarm" -> {
|
|
|
|
|
|
|
|
val hour = call.argument<Int>("hour") ?: 0
|
|
|
|
|
|
|
|
val minute = call.argument<Int>("minute") ?: 15
|
|
|
|
|
|
|
|
Log.d(TAG, "Scheduling restart alarm for $hour:$minute")
|
|
|
|
|
|
|
|
scheduleRestartAlarm(hour, minute)
|
|
|
|
|
|
|
|
result.success("Restart alarm scheduled for $hour:$minute")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"cancelRestartAlarm" -> {
|
|
|
|
|
|
|
|
Log.d(TAG, "Cancelling restart alarm")
|
|
|
|
|
|
|
|
AlarmScheduler.cancelRestartAlarm(this)
|
|
|
|
|
|
|
|
result.success("Restart alarm cancelled")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"canScheduleExactAlarms" -> {
|
|
|
|
|
|
|
|
val canSchedule = AlarmScheduler.canScheduleExactAlarms(this)
|
|
|
|
|
|
|
|
Log.d(TAG, "Can schedule exact alarms: $canSchedule")
|
|
|
|
|
|
|
|
result.success(canSchedule)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"requestExactAlarmPermission" -> {
|
|
|
|
|
|
|
|
Log.d(TAG, "Requesting exact alarm permission")
|
|
|
|
|
|
|
|
AlarmScheduler.requestExactAlarmPermission(this)
|
|
|
|
|
|
|
|
result.success("Permission request initiated")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
else -> {
|
|
|
|
else -> {
|
|
|
|
Log.w("MainActivity", "Method not implemented: ${call.method}")
|
|
|
|
Log.w(TAG, "Method not implemented: ${call.method}")
|
|
|
|
result.notImplemented()
|
|
|
|
result.notImplemented()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private fun restartApplication() {
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Schedule daily restart alarm at specified time.
|
|
|
|
|
|
|
|
* Compatible with Android 14+ and older versions.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private fun scheduleRestartAlarm(hour: Int, minute: Int) {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
Log.d("MainActivity", "Initiating app restart")
|
|
|
|
AlarmScheduler.scheduleRestartAlarm(this, hour, minute)
|
|
|
|
|
|
|
|
Log.d(TAG, "Restart alarm scheduled successfully for $hour:$minute")
|
|
|
|
|
|
|
|
} catch (e: Exception) {
|
|
|
|
|
|
|
|
Log.e(TAG, "Error scheduling restart alarm: ${e.message}")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Clear resources before restart
|
|
|
|
private fun restartApplication() {
|
|
|
|
clearAllNativeResources()
|
|
|
|
try {
|
|
|
|
|
|
|
|
Log.d(TAG, "Initiating app restart")
|
|
|
|
|
|
|
|
|
|
|
|
// Create restart intent
|
|
|
|
// Get the launch intent
|
|
|
|
val intent = packageManager.getLaunchIntentForPackage(packageName)?.apply {
|
|
|
|
val intent = packageManager.getLaunchIntentForPackage(packageName)
|
|
|
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
|
|
|
|
|
|
|
putExtra("restarted", true)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (intent != null) {
|
|
|
|
if (intent != null) {
|
|
|
|
// Use a shorter delay for faster restart
|
|
|
|
// Configure intent for clean restart
|
|
|
|
|
|
|
|
intent.apply {
|
|
|
|
|
|
|
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
|
|
|
|
|
|
|
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
|
|
|
|
|
|
|
putExtra("restarted", true)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Use AlarmManager for reliable restart (works better on Android 14+)
|
|
|
|
|
|
|
|
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
|
|
|
|
|
|
|
val pendingIntent = PendingIntent.getActivity(
|
|
|
|
|
|
|
|
this,
|
|
|
|
|
|
|
|
0,
|
|
|
|
|
|
|
|
intent,
|
|
|
|
|
|
|
|
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Schedule restart in 500ms
|
|
|
|
|
|
|
|
alarmManager.set(
|
|
|
|
|
|
|
|
AlarmManager.RTC,
|
|
|
|
|
|
|
|
System.currentTimeMillis() + 500,
|
|
|
|
|
|
|
|
pendingIntent
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Log.d(TAG, "Restart scheduled via AlarmManager")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Now safely exit the app
|
|
|
|
Handler(Looper.getMainLooper()).postDelayed({
|
|
|
|
Handler(Looper.getMainLooper()).postDelayed({
|
|
|
|
startActivity(intent)
|
|
|
|
|
|
|
|
finishAffinity()
|
|
|
|
finishAffinity()
|
|
|
|
// Remove exitProcess() call if present
|
|
|
|
android.os.Process.killProcess(android.os.Process.myPid())
|
|
|
|
// android.os.Process.killProcess(android.os.Process.myPid())
|
|
|
|
}, 100)
|
|
|
|
}, 100) // Reduced delay
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Log.d("MainActivity", "App restart initiated")
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Log.e("MainActivity", "Could not create restart intent")
|
|
|
|
Log.e(TAG, "Could not create restart intent")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} catch (e: Exception) {
|
|
|
|
|
|
|
|
Log.e(TAG, "Error during restart: ${e.message}")
|
|
|
|
|
|
|
|
// Fallback: try simple restart
|
|
|
|
|
|
|
|
fallbackRestart()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Fallback restart method if AlarmManager approach fails
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private fun fallbackRestart() {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
Log.d(TAG, "Attempting fallback restart")
|
|
|
|
|
|
|
|
val intent = packageManager.getLaunchIntentForPackage(packageName)?.apply {
|
|
|
|
|
|
|
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
|
|
|
|
|
|
|
putExtra("restarted", true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (intent != null) {
|
|
|
|
|
|
|
|
startActivity(intent)
|
|
|
|
|
|
|
|
finishAffinity()
|
|
|
|
|
|
|
|
Runtime.getRuntime().exit(0)
|
|
|
|
|
|
|
|
}
|
|
|
|
} catch (e: Exception) {
|
|
|
|
} catch (e: Exception) {
|
|
|
|
Log.e("MainActivity", "Error during restart: ${e.message}")
|
|
|
|
Log.e(TAG, "Fallback restart also failed: ${e.message}")
|
|
|
|
// Fallback - don't exit, just log the error
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -237,25 +323,43 @@ class MainActivity : FlutterActivity() {
|
|
|
|
|
|
|
|
|
|
|
|
// Log if app was restarted
|
|
|
|
// Log if app was restarted
|
|
|
|
if (intent.getBooleanExtra("restarted", false)) {
|
|
|
|
if (intent.getBooleanExtra("restarted", false)) {
|
|
|
|
Log.d("MainActivity", "App restarted successfully")
|
|
|
|
Log.d(TAG, "App restarted successfully")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Log if launched from boot
|
|
|
|
// Log if launched from boot
|
|
|
|
if (intent.getBooleanExtra("launched_from_boot", false)) {
|
|
|
|
if (intent.getBooleanExtra("launched_from_boot", false)) {
|
|
|
|
Log.d("MainActivity", "App launched from boot")
|
|
|
|
Log.d(TAG, "App launched from boot")
|
|
|
|
// Give system time to settle after boot
|
|
|
|
// Give system time to settle after boot
|
|
|
|
Thread.sleep(2000)
|
|
|
|
Thread.sleep(2000)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Schedule daily restart alarm at 00:15 (12:15 AM)
|
|
|
|
|
|
|
|
// This ensures the alarm is always set when app starts
|
|
|
|
|
|
|
|
initializeRestartAlarm()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Initialize the daily restart alarm.
|
|
|
|
|
|
|
|
* Called on app start to ensure alarm is always scheduled.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private fun initializeRestartAlarm() {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
Log.d(TAG, "Initializing daily restart alarm")
|
|
|
|
|
|
|
|
AlarmScheduler.scheduleRestartAlarm(this, 0, 15) // 00:15 (12:15 AM)
|
|
|
|
|
|
|
|
Log.d(TAG, "Daily restart alarm initialized for 00:15")
|
|
|
|
|
|
|
|
} catch (e: Exception) {
|
|
|
|
|
|
|
|
Log.e(TAG, "Error initializing restart alarm: ${e.message}")
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
override fun onResume() {
|
|
|
|
override fun onResume() {
|
|
|
|
super.onResume()
|
|
|
|
super.onResume()
|
|
|
|
Log.d("MainActivity", "Activity resumed")
|
|
|
|
Log.d(TAG, "Activity resumed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
override fun onPause() {
|
|
|
|
override fun onPause() {
|
|
|
|
super.onPause()
|
|
|
|
super.onPause()
|
|
|
|
Log.d("MainActivity", "Activity paused - cleaning up resources")
|
|
|
|
Log.d(TAG, "Activity paused - cleaning up resources")
|
|
|
|
|
|
|
|
|
|
|
|
// Light cleanup when app goes to background
|
|
|
|
// Light cleanup when app goes to background
|
|
|
|
System.gc()
|
|
|
|
System.gc()
|
|
|
|
@ -263,7 +367,7 @@ class MainActivity : FlutterActivity() {
|
|
|
|
|
|
|
|
|
|
|
|
override fun onDestroy() {
|
|
|
|
override fun onDestroy() {
|
|
|
|
super.onDestroy()
|
|
|
|
super.onDestroy()
|
|
|
|
Log.d("MainActivity", "Activity destroyed")
|
|
|
|
Log.d(TAG, "Activity destroyed")
|
|
|
|
|
|
|
|
|
|
|
|
// Final cleanup
|
|
|
|
// Final cleanup
|
|
|
|
clearAllNativeResources()
|
|
|
|
clearAllNativeResources()
|
|
|
|
|