1 Commits

Author SHA1 Message Date
bdd458a64f UPDATE: Add wakelock 2025-08-06 18:32:18 +07:00
3 changed files with 56 additions and 27 deletions

View File

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

View File

@@ -8,29 +8,39 @@ import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.os.PowerManager
import android.util.Log
import androidx.core.app.NotificationCompat
import libandroid.Libandroid
class GolangServerService : Service() {
companion object {
const val CHANNEL_ID = "GolangServerChannel"
const val NOTIFICATION_ID = 1
private const val TAG = "GolangServerService"
}
private var wakeLock: PowerManager.WakeLock? = null
override fun onCreate() {
super.onCreate()
createNotificationChannel()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d(TAG, "onStartCommand called")
// 1. Tạo intent để mở lại MainActivity khi người dùng click vào thông báo
val notificationIntent = Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(
this, 0, notificationIntent,
PendingIntent.FLAG_IMMUTABLE
this,
0,
notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
// 2. Tạo notification
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Golang Server")
.setContentText("Server đang chạy")
@@ -38,13 +48,23 @@ class GolangServerService : Service() {
.setContentIntent(pendingIntent)
.build()
// 3. Chạy foreground
startForeground(NOTIFICATION_ID, notification)
// Chạy server trong thread riêng để tránh ANR
// 4. Giữ CPU không sleep (tùy chọn, nhưng hữu ích)
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)
}
// 5. Chạy server trong thread riêng
Thread {
try {
val appDataPath = intent?.getStringExtra("appDataPath")
if (appDataPath != null) {
Libandroid.setPathDataLocal(appDataPath)
Log.d(TAG, "✅ Set path data: $appDataPath")
@@ -55,7 +75,7 @@ class GolangServerService : Service() {
Libandroid.setServerRunning(true)
Log.d(TAG, "✅ Server started")
} catch (e: Exception) {
Log.e(TAG, "❌ Error when start server:", e)
Log.e(TAG, "❌ Error starting server", e)
}
}.start()
@@ -64,17 +84,30 @@ class GolangServerService : Service() {
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy called")
// 1. Tắt server
try {
val result = Libandroid.setServerRunning(false)
Log.d(TAG, "Server shutdown result: $result")
} catch (e: Exception) {
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)
}
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onBind(intent: Intent?): IBinder? = null
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -83,11 +116,12 @@ class GolangServerService : Service() {
"Golang Server Channel",
NotificationManager.IMPORTANCE_LOW
).apply {
description = "Notify Golang backend runing"
description = "Channel for running Golang backend in foreground"
}
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
manager.createNotificationChannel(channel)
Log.d(TAG, "✅ Notification channel created")
}
}
}

View File

@@ -1,5 +1,6 @@
package com.example.fireflypsandorid
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.util.Log
@@ -8,13 +9,11 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.*
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
@@ -26,7 +25,7 @@ import com.example.fireflypsandorid.ui.theme.FireflyPsAndoridTheme
import java.io.*
class MainActivity : ComponentActivity() {
private val TAG = "AppInit"
private val tag = "AppInit"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -58,17 +57,18 @@ class MainActivity : ComponentActivity() {
input.copyTo(output)
}
}
Log.i(TAG, "✅ Copied $fileName to ${outFile.absolutePath}")
Log.i(tag, "✅ Copied $fileName to ${outFile.absolutePath}")
} catch (e: Exception) {
Log.e(TAG, "❌ Failed to copy $fileName: ${e.message}")
Log.e(tag, "❌ Failed to copy $fileName: ${e.message}")
}
} else {
Log.i(TAG, " $fileName already exists at ${outFile.absolutePath}")
Log.i(tag, " $fileName already exists at ${outFile.absolutePath}")
}
}
}
@SuppressLint("ImplicitSamInstance")
@Composable
fun ServerControlScreen(appDataPath: String, modifier: Modifier = Modifier) {
val context = LocalContext.current
@@ -128,7 +128,7 @@ fun ServerControlScreen(appDataPath: String, modifier: Modifier = Modifier) {
}
},
colors = ButtonDefaults.buttonColors(
containerColor = if (isServerRunning) Color(0xFFB71C1C) else Color(0xFFFF5722),
containerColor = if (isServerRunning) Color(0xFFB71C1C) else Color(0xFF2196F3),
contentColor = Color.White
),
shape = RoundedCornerShape(12.dp),