diff --git a/.idea/misc.xml b/.idea/misc.xml index 6c5519f..3b0be22 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,3 +1,4 @@ + diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6493094..1cad631 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -21,7 +21,6 @@ android { defaultConfig { applicationId = "com.kain344.firefly_go_android" minSdk = 24 - //noinspection OldTargetApi targetSdk = 35 versionCode = 1 versionName = "1.0" diff --git a/app/libs/firefly-go.aar b/app/libs/firefly-go.aar index cff08e6..41105d1 100644 --- a/app/libs/firefly-go.aar +++ b/app/libs/firefly-go.aar @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:00e4ded474cd4f9543e38b169e104463143342632417ce13723cfde4f166e9a4 -size 28430686 +oid sha256:d338b769409a6d8fdd57990d2db18ac93b860fa02ad64d6a7ad5a799c0b628ee +size 13923740 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8e91664..c123ba3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,12 +2,20 @@ - - + + + + - + + + + + + - + android:foregroundServiceType="specialUse" + android:exported="false"> + + = 34) { + startForeground( + NOTIFICATION_ID, + notification, + ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE + ) + } else if (Build.VERSION.SDK_INT >= 29) { + startForeground( + NOTIFICATION_ID, + notification, + ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST + ) + } else { + startForeground(NOTIFICATION_ID, notification) + } - startForeground(NOTIFICATION_ID, notification) - + // Khởi tạo WakeLock và WifiLock try { val powerManager = getSystemService(POWER_SERVICE) as PowerManager wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "GolangServer::WakeLock") - wakeLock?.acquire(10*60*1000L) - Log.d(TAG, "✅ WakeLock acquired") + wakeLock?.acquire() + Log.d(TAG, "WakeLock acquired") } catch (e: Exception) { - Log.e(TAG, "❌ WakeLock failed", e) + Log.e(TAG, "Lock failed", e) } Thread { try { - val appDataPath = intent?.getStringExtra("appDataPath") + val sharedPrefs = getSharedPreferences("AppPrefs", MODE_PRIVATE) + var appDataPath = intent?.getStringExtra("appDataPath") + + if (appDataPath != null) { + sharedPrefs.edit { putString("saved_app_data_path", appDataPath) } + } else { + appDataPath = sharedPrefs.getString("saved_app_data_path", null) + } + if (appDataPath != null) { Libandroid.setPathDataLocal(appDataPath) - Log.d(TAG, "✅ Set path data: $appDataPath") + Log.d(TAG, "Set path data: $appDataPath") } else { isRunning = false - Log.e(TAG, "❌ appDataPath not received in intent") + Log.e(TAG, "appDataPath not received and not found in SharedPreferences") stopSelf() return@Thread } Libandroid.setServerRunning(true) isRunning = true - Log.d(TAG, "✅ Server started") + Log.d(TAG, "Server started") } catch (e: Exception) { isRunning = false - Log.e(TAG, "❌ Error starting server", e) + Log.e(TAG, "Error starting server", e) stopSelf() } }.start() - return START_STICKY } @@ -107,7 +132,6 @@ class GolangServerService : Service() { super.onDestroy() Log.d(TAG, "onDestroy called") - // 1. Tắt server try { val result = Libandroid.setServerRunning(false) isRunning = false @@ -116,15 +140,16 @@ class GolangServerService : Service() { Log.e(TAG, "Error shutting down server", e) } + // Nhả các khóa tài nguyên try { wakeLock?.let { if (it.isHeld) { it.release() - Log.d(TAG, "✅ WakeLock released") + Log.d(TAG, "WakeLock released") } } } catch (e: Exception) { - Log.e(TAG, "❌ Failed to release WakeLock", e) + Log.e(TAG, "Failed to release Locks", e) } isRunning = false } @@ -143,7 +168,7 @@ class GolangServerService : Service() { val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager manager.createNotificationChannel(channel) - Log.d(TAG, "✅ Notification channel created") + Log.d(TAG, "Notification channel created") } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/example/firefly_go_android/MainActivity.kt b/app/src/main/java/com/example/firefly_go_android/MainActivity.kt index d974fda..4483d3a 100644 --- a/app/src/main/java/com/example/firefly_go_android/MainActivity.kt +++ b/app/src/main/java/com/example/firefly_go_android/MainActivity.kt @@ -4,8 +4,9 @@ import AutoUpdaterManager import android.annotation.SuppressLint import android.content.Context import android.content.Intent +import android.os.Build import android.os.Bundle - +import android.os.Environment import android.util.Log import android.widget.Toast import androidx.activity.ComponentActivity @@ -67,6 +68,11 @@ import kotlinx.coroutines.delay import org.json.JSONObject import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontFamily +import android.os.PowerManager +import android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS +import androidx.core.content.ContextCompat +import androidx.core.net.toUri +import android.provider.Settings data class AppVersion( val latestVersion: String, @@ -77,14 +83,14 @@ data class AppVersion( class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + requestBatteryExemption(this) + requestInstallPermission(this) - val appDataPath = filesDir.absolutePath + val appDataPath = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "FireflyGo").absolutePath val dataDir = File("$appDataPath/data") - dataDir.mkdirs() + if (!dataDir.exists()) dataDir.mkdirs() - copyRawToFile(this, dataDir, "data-in-game.json", R.raw.data_in_game_json) - copyRawToFile(this, dataDir, "freesr-data.json", R.raw.freesr_data_json) - copyRawToFile(this, dataDir, "version.json", R.raw.version_json) + copyRawToFile(dataDir) val jsonString = resources.openRawResource(R.raw.app_version_json).use { input -> input.bufferedReader().use { it.readText() } @@ -112,22 +118,61 @@ class MainActivity : ComponentActivity() { } } +@SuppressLint("BatteryLife") -fun copyRawToFile(context: Context, targetDir: File, fileName: String, resId: Int, override: Boolean = false) { - val outFile = File(targetDir, fileName) - if (!outFile.exists() || override) { - try { - context.resources.openRawResource(resId).use { input -> +fun requestBatteryExemption(context: Context) { + val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager + if (!powerManager.isIgnoringBatteryOptimizations(context.packageName)) { + val intent = Intent().apply { + action = ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS + data = "package:${context.packageName}".toUri() + } + context.startActivity(intent) + } +} + +fun requestInstallPermission(context: Context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (!context.packageManager.canRequestPackageInstalls()) { + val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).apply { + data = "package:${context.packageName}".toUri() + } + context.startActivity(intent) + Toast.makeText(context, "Please allow installing unknown apps to update", Toast.LENGTH_LONG).show() + } + } +} +fun copyRawToFile(targetDir: File, override: Boolean = false): Boolean { + val files = listOf( + "assets/data-in-game.json" to "data-in-game.json", + "assets/freesr-data.json" to "freesr-data.json", + "assets/version.json" to "version.json" + ) + + return try { + if (!targetDir.exists()) targetDir.mkdirs() + + for ((assetPath, name) in files) { + val outFile = File(targetDir, name) + + if (outFile.exists() && !override) continue + + val inputStream = + MainActivity::class.java.classLoader + ?.getResourceAsStream(assetPath) + ?: return false + + inputStream.use { input -> FileOutputStream(outFile).use { output -> input.copyTo(output) + output.fd.sync() } } - Log.i("FileCopy", "${if (override) "✅ Overridden" else "✅ Copied"} $fileName to ${outFile.absolutePath}") - } catch (e: Exception) { - Log.e("FileCopy", "❌ Failed to copy $fileName: ${e.message}") } - } else { - Log.i("FileCopy", "ℹ️ $fileName already exists at ${outFile.absolutePath}") + + true + } catch (e: Exception) { + false } } @@ -136,18 +181,18 @@ fun removeFile(targetDir: File, fileName: String): Boolean { return if (file.exists()) { try { if (file.delete()) { - Log.i("FileRemove", "🗑️ Removed $fileName from ${file.absolutePath}") + Log.i("FileRemove", "Removed $fileName from ${file.absolutePath}") true } else { - Log.e("FileRemove", "❌ Failed to remove $fileName from ${file.absolutePath}") + Log.e("FileRemove", "Failed to remove $fileName from ${file.absolutePath}") false } } catch (e: Exception) { - Log.e("FileRemove", "❌ Error removing $fileName: ${e.message}") + Log.e("FileRemove", "Error removing $fileName: ${e.message}") false } } else { - Log.i("FileRemove", "ℹ️ $fileName does not exist in ${targetDir.absolutePath}") + Log.i("FileRemove", "$fileName does not exist in ${targetDir.absolutePath}") false } } @@ -239,7 +284,7 @@ fun ServerControlScreen(appDataPath: String, dataDir: File, appVersion: AppVersi if (!isRunning) { val intent = Intent(context, GolangServerService::class.java) intent.putExtra("appDataPath", appDataPath) - context.startService(intent) + ContextCompat.startForegroundService(context, intent) } else { context.stopService(Intent(context, GolangServerService::class.java)) } @@ -382,9 +427,7 @@ fun ServerControlScreen(appDataPath: String, dataDir: File, appVersion: AppVersi onClick = { showResetDialog = false try { - copyRawToFile(context, dataDir, "data-in-game.json", R.raw.data_in_game_json, true) - copyRawToFile(context, dataDir, "freesr-data.json", R.raw.freesr_data_json, true) - copyRawToFile(context, dataDir, "version.json", R.raw.version_json, true) + copyRawToFile(dataDir, true) Toast.makeText(context, "Data has been reset successfully", Toast.LENGTH_SHORT).show() } catch (e: Exception) { Toast.makeText(context, "Reset failed: ${e.message}", Toast.LENGTH_SHORT).show() diff --git a/app/src/main/res/raw/app_version_json.json b/app/src/main/res/raw/app_version_json.json index 2858218..69bb764 100644 --- a/app/src/main/res/raw/app_version_json.json +++ b/app/src/main/res/raw/app_version_json.json @@ -1,5 +1,5 @@ { - "latest_version": "4.1.1-01", - "changelog": "UPDATE: 4.1.51", - "apk_url": "https://git.kain.io.vn/Firefly-Shelter/FireflyGo_Android/releases/download/4.1.1-01/firefly_go_android.apk" + "latest_version": "4.1.2-01", + "changelog": "UPDATE: 4.1.52", + "apk_url": "https://git.kain.io.vn/Firefly-Shelter/FireflyGo_Android/releases/download/4.1.2-01/firefly_go_android.apk" } \ No newline at end of file diff --git a/script/release.json b/script/release.json index ee6d04c..f5bd32c 100644 --- a/script/release.json +++ b/script/release.json @@ -1,4 +1,4 @@ { - "tag": "4.1.1-01", - "title": "PreBuild Version 4.1.51 - 01" + "tag": "4.1.2-01", + "title": "PreBuild Version 4.1.52 - 01" } \ No newline at end of file