UPDATE: Add wakelock

This commit is contained in:
2025-08-06 18:32:18 +07:00
parent 93d86df411
commit bdd458a64f
3 changed files with 56 additions and 27 deletions

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,29 +8,39 @@ 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.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"
} }
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 {
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 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
) )
// 2. Tạo notification
val notification = NotificationCompat.Builder(this, CHANNEL_ID) val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Golang Server") .setContentTitle("Golang Server")
.setContentText("Server đang chạy") .setContentText("Server đang chạy")
@@ -38,13 +48,23 @@ class GolangServerService : Service() {
.setContentIntent(pendingIntent) .setContentIntent(pendingIntent)
.build() .build()
// 3. Chạy foreground
startForeground(NOTIFICATION_ID, notification) 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 { 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")
@@ -55,7 +75,7 @@ class GolangServerService : Service() {
Libandroid.setServerRunning(true) Libandroid.setServerRunning(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) Log.e(TAG, "❌ Error starting server", e)
} }
}.start() }.start()
@@ -64,17 +84,30 @@ class GolangServerService : Service() {
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)
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)
}
} }
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 +116,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,17 +57,18 @@ 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
@@ -128,7 +128,7 @@ fun ServerControlScreen(appDataPath: String, modifier: Modifier = Modifier) {
} }
}, },
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
containerColor = if (isServerRunning) Color(0xFFB71C1C) else Color(0xFFFF5722), containerColor = if (isServerRunning) Color(0xFFB71C1C) else Color(0xFF2196F3),
contentColor = Color.White contentColor = Color.White
), ),
shape = RoundedCornerShape(12.dp), shape = RoundedCornerShape(12.dp),