3 Commits

Author SHA1 Message Date
ed411fc284 UPDATE: update for 3.5.1 2025-08-19 11:18:08 +07:00
b7b0457685 FIX: app runing state bug 2025-08-06 19:09:41 +07:00
bdd458a64f UPDATE: Add wakelock 2025-08-06 18:32:18 +07:00
6 changed files with 80 additions and 40 deletions

Binary file not shown.

View File

@@ -3,13 +3,9 @@
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<application <application
android:allowBackup="true" android:allowBackup="true"
@@ -25,18 +21,17 @@
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.FireflyPsAndorid"> android:theme="@style/Theme.FireflyPsAndorid">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<service <service
android:name=".GolangServerService" android:name=".GolangServerService"
android:foregroundServiceType="dataSync" /> android:foregroundServiceType="dataSync"
android:exported="false" />
</application> </application>
</manifest> </manifest>

View File

@@ -8,73 +8,119 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Build import android.os.Build
import android.os.IBinder import android.os.IBinder
import android.os.PowerManager
import android.util.Log import android.util.Log
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import libandroid.Libandroid import libandroid.Libandroid
class GolangServerService : Service() { class GolangServerService : Service() {
companion object { companion object {
const val CHANNEL_ID = "GolangServerChannel" const val CHANNEL_ID = "GolangServerChannel"
const val NOTIFICATION_ID = 1 const val NOTIFICATION_ID = 1
private const val TAG = "GolangServerService" private const val TAG = "GolangServerService"
var isRunning by mutableStateOf(false)
} }
private var wakeLock: PowerManager.WakeLock? = null
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
createNotificationChannel() createNotificationChannel()
} }
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (isRunning) {
Log.d(TAG, "❗ Server is already running")
return START_STICKY
}
isRunning = true
Log.d(TAG, "onStartCommand called")
val notificationIntent = Intent(this, MainActivity::class.java) val notificationIntent = Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity( val pendingIntent = PendingIntent.getActivity(
this, 0, notificationIntent, this,
PendingIntent.FLAG_IMMUTABLE 0,
notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
) )
val notification = NotificationCompat.Builder(this, CHANNEL_ID) val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Golang Server") .setContentTitle("FireflyGO Server")
.setContentText("Server đang chạy") .setContentText("FireflyGO is running...")
.setSmallIcon(R.drawable.ic_launcher_foreground) .setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentIntent(pendingIntent) .setContentIntent(pendingIntent)
.build() .build()
startForeground(NOTIFICATION_ID, notification) startForeground(NOTIFICATION_ID, notification)
// Chạy server trong thread riêng để tránh ANR try {
val powerManager = getSystemService(POWER_SERVICE) as PowerManager
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "GolangServer::WakeLock")
wakeLock?.acquire()
Log.d(TAG, "✅ WakeLock acquired")
} catch (e: Exception) {
Log.e(TAG, "❌ WakeLock failed", e)
}
Thread { Thread {
try { try {
val appDataPath = intent?.getStringExtra("appDataPath") val appDataPath = intent?.getStringExtra("appDataPath")
if (appDataPath != null) { if (appDataPath != null) {
Libandroid.setPathDataLocal(appDataPath) Libandroid.setPathDataLocal(appDataPath)
Log.d(TAG, "✅ Set path data: $appDataPath") Log.d(TAG, "✅ Set path data: $appDataPath")
} else { } else {
isRunning = false
Log.e(TAG, "❌ appDataPath not received in intent") Log.e(TAG, "❌ appDataPath not received in intent")
stopSelf()
return@Thread
} }
Libandroid.setServerRunning(true) Libandroid.setServerRunning(true)
isRunning = true
Log.d(TAG, "✅ Server started") Log.d(TAG, "✅ Server started")
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "❌ Error when start server:", e) isRunning = false
Log.e(TAG, "❌ Error starting server", e)
stopSelf()
} }
}.start() }.start()
return START_STICKY return START_STICKY
} }
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
Log.d(TAG, "onDestroy called")
// 1. Tắt server
try { try {
val result = Libandroid.setServerRunning(false) val result = Libandroid.setServerRunning(false)
isRunning = false
Log.d(TAG, "Server shutdown result: $result") Log.d(TAG, "Server shutdown result: $result")
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Error shutting down server", e) Log.e(TAG, "Error shutting down server", e)
} }
// 2. Giải phóng WakeLock nếu còn giữ
try {
wakeLock?.let {
if (it.isHeld) {
it.release()
Log.d(TAG, "✅ WakeLock released")
}
}
} catch (e: Exception) {
Log.e(TAG, "❌ Failed to release WakeLock", e)
}
isRunning = false
} }
override fun onBind(intent: Intent?): IBinder? { override fun onBind(intent: Intent?): IBinder? = null
return null
}
private fun createNotificationChannel() { private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -83,11 +129,12 @@ class GolangServerService : Service() {
"Golang Server Channel", "Golang Server Channel",
NotificationManager.IMPORTANCE_LOW NotificationManager.IMPORTANCE_LOW
).apply { ).apply {
description = "Notify Golang backend runing" description = "Channel for running Golang backend in foreground"
} }
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel) manager.createNotificationChannel(channel)
Log.d(TAG, "✅ Notification channel created")
} }
} }
} }

View File

@@ -1,5 +1,6 @@
package com.example.fireflypsandorid package com.example.fireflypsandorid
import android.annotation.SuppressLint
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
@@ -8,13 +9,11 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.* import androidx.compose.ui.*
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
@@ -26,7 +25,7 @@ import com.example.fireflypsandorid.ui.theme.FireflyPsAndoridTheme
import java.io.* import java.io.*
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
private val TAG = "AppInit" private val tag = "AppInit"
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -58,23 +57,23 @@ class MainActivity : ComponentActivity() {
input.copyTo(output) input.copyTo(output)
} }
} }
Log.i(TAG, "✅ Copied $fileName to ${outFile.absolutePath}") Log.i(tag, "✅ Copied $fileName to ${outFile.absolutePath}")
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "❌ Failed to copy $fileName: ${e.message}") Log.e(tag, "❌ Failed to copy $fileName: ${e.message}")
} }
} else { } else {
Log.i(TAG, " $fileName already exists at ${outFile.absolutePath}") Log.i(tag, " $fileName already exists at ${outFile.absolutePath}")
} }
} }
} }
@SuppressLint("ImplicitSamInstance")
@Composable @Composable
fun ServerControlScreen(appDataPath: String, modifier: Modifier = Modifier) { fun ServerControlScreen(appDataPath: String, modifier: Modifier = Modifier) {
val context = LocalContext.current val context = LocalContext.current
var isServerRunning by remember { mutableStateOf(false) } val isRunning = GolangServerService.isRunning
val serverImage = if (isRunning)
val serverImage = if (isServerRunning)
painterResource(id = R.drawable.server_running) painterResource(id = R.drawable.server_running)
else else
painterResource(id = R.drawable.server_stopped) painterResource(id = R.drawable.server_stopped)
@@ -115,8 +114,7 @@ fun ServerControlScreen(appDataPath: String, modifier: Modifier = Modifier) {
Button( Button(
onClick = { onClick = {
try { try {
isServerRunning = !isServerRunning if (!isRunning) {
if (isServerRunning) {
val intent = Intent(context, GolangServerService::class.java) val intent = Intent(context, GolangServerService::class.java)
intent.putExtra("appDataPath", appDataPath) intent.putExtra("appDataPath", appDataPath)
context.startService(intent) context.startService(intent)
@@ -128,7 +126,7 @@ fun ServerControlScreen(appDataPath: String, modifier: Modifier = Modifier) {
} }
}, },
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
containerColor = if (isServerRunning) Color(0xFFB71C1C) else Color(0xFFFF5722), containerColor = if (isRunning) Color(0xFFB71C1C) else Color(0xFF2196F3),
contentColor = Color.White contentColor = Color.White
), ),
shape = RoundedCornerShape(12.dp), shape = RoundedCornerShape(12.dp),
@@ -137,7 +135,7 @@ fun ServerControlScreen(appDataPath: String, modifier: Modifier = Modifier) {
.height(50.dp) .height(50.dp)
) { ) {
Text( Text(
text = if (isServerRunning) "Stop Server" else "Start Server", text = if (isRunning) "Stop Server" else "Start Server",
fontSize = 20.sp fontSize = 20.sp
) )
} }
@@ -146,9 +144,9 @@ fun ServerControlScreen(appDataPath: String, modifier: Modifier = Modifier) {
// Server status text // Server status text
Text( Text(
text = if (isServerRunning) "Server is running" else "Server is stopped", text = if (isRunning) "Server is running" else "Server is stopped",
fontSize = 24.sp, fontSize = 24.sp,
color = if (isServerRunning) Color(0xFF4CAF50) else Color.Gray color = if (isRunning) Color(0xFF4CAF50) else Color.Gray
) )
Spacer(modifier = Modifier.height(24.dp)) Spacer(modifier = Modifier.height(24.dp))

View File

@@ -1,3 +1,3 @@
<resources> <resources>
<string name="app_name">FireflyGo-3.4.5X</string> <string name="app_name">FireflyGo-3.5.5X</string>
</resources> </resources>

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:ab23bd9a708e04ce0817aa7e3d05e81e3bd64e8846d0df54af9647b550d30859 oid sha256:26eaf2a6981aed15c5c7f6edc465505406f05567739054e71f2d3af60f111ef2
size 72329407 size 73415308