feat: implement authentication management and deep link handling in MainActivity and GolangServerService
Build / build (push) Failing after 3m36s

This commit is contained in:
2026-06-25 23:55:16 +07:00
parent 1ae12e94bc
commit c2bd81fc75
10 changed files with 11 additions and 400 deletions
-3
View File
@@ -83,15 +83,12 @@ dependencies {
// Auto updater library
implementation(libs.autoupdater)
<<<<<<< HEAD
=======
// OkHttp Client
implementation("com.squareup.okhttp3:okhttp:4.12.0")
// Chrome Custom Tabs
implementation("androidx.browser:browser:1.8.0")
>>>>>>> 2459650 (feat: v4)
// Unit Test
testImplementation(libs.junit)
-66
View File
@@ -1,68 +1,3 @@
<<<<<<< HEAD
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"
tools:ignore="ForegroundServicesPolicy" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"
tools:ignore="RequestInstallPackagesPolicy" />
<uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:requestLegacyExternalStorage="true"
android:theme="@style/Theme.FireflyGoAndroid"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.FireflyGoAndroid">
<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="specialUse"
android:exported="false">
<property
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
android:value="Running local Golang TCP/UDP Server" />
</service>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
=======
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
@@ -134,5 +69,4 @@
</provider>
</application>
>>>>>>> 2459650 (feat: v4)
</manifest>
@@ -1,4 +1,3 @@
<<<<<<< HEAD
package com.example.firefly_go_android
import android.annotation.SuppressLint
@@ -172,179 +171,4 @@ class GolangServerService : Service() {
Log.d(TAG, "Notification channel created")
}
}
=======
package com.example.firefly_go_android
import android.annotation.SuppressLint
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Intent
import android.content.pm.ServiceInfo
import android.graphics.BitmapFactory
import android.os.Build
import android.os.IBinder
import android.os.PowerManager
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.content.ContextCompat
import libandroid.Libandroid
import androidx.core.content.edit
class GolangServerService : Service() {
companion object {
const val CHANNEL_ID = "GolangServerChannel"
const val NOTIFICATION_ID = 1
private const val TAG = "GolangServerService"
var isRunning by mutableStateOf(false)
}
private var wakeLock: PowerManager.WakeLock? = null
override fun onCreate() {
super.onCreate()
createNotificationChannel()
}
@SuppressLint("WakelockTimeout")
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 pendingIntent = PendingIntent.getActivity(
this,
0,
notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val largeIcon = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher)
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher_round)
.setLargeIcon(largeIcon)
.setContentTitle("FireflyGO Server")
.setContentText("Server is running...")
.setColor(ContextCompat.getColor(this, R.color.teal_700))
.setOngoing(true)
.setOnlyAlertOnce(true)
.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setShowWhen(false)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.build()
if (Build.VERSION.SDK_INT >= 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)
}
// 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()
Log.d(TAG, "WakeLock acquired")
} catch (e: Exception) {
Log.e(TAG, "Lock failed", e)
}
Thread {
try {
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")
} else {
isRunning = false
Log.e(TAG, "appDataPath not received and not found in SharedPreferences")
stopSelf()
return@Thread
}
Libandroid.setServerRunning(true)
isRunning = true
Log.d(TAG, "Server started")
} catch (e: Exception) {
isRunning = false
Log.e(TAG, "Error starting server", e)
stopSelf()
}
}.start()
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy called")
try {
val result = Libandroid.setServerRunning(false)
isRunning = false
Log.d(TAG, "Server shutdown result: $result")
} catch (e: Exception) {
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")
}
}
} catch (e: Exception) {
Log.e(TAG, "Failed to release Locks", e)
}
isRunning = false
}
override fun onBind(intent: Intent?): IBinder? = null
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
CHANNEL_ID,
"Golang Server Channel",
NotificationManager.IMPORTANCE_LOW
).apply {
description = "Channel for running Golang backend in foreground"
}
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
manager.createNotificationChannel(channel)
Log.d(TAG, "Notification channel created")
}
}
>>>>>>> 2459650 (feat: v4)
}
@@ -33,16 +33,11 @@ import androidx.compose.animation.*
import androidx.compose.animation.core.*
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
<<<<<<< HEAD
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
=======
import androidx.compose.foundation.border
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
>>>>>>> 2459650 (feat: v4)
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.BugReport
@@ -82,14 +77,11 @@ import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import android.provider.Settings
<<<<<<< HEAD
=======
import com.example.firefly_go_android.network.AuthManager
import com.example.firefly_go_android.ui.ScamWarningDialog
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
>>>>>>> 2459650 (feat: v4)
data class AppVersion(
val latestVersion: String,
val changelog: String,
@@ -97,33 +89,23 @@ data class AppVersion(
)
class MainActivity : ComponentActivity() {
<<<<<<< HEAD
=======
private lateinit var authManager: AuthManager
private var onAuthStatusChanged: (() -> Unit)? = null
>>>>>>> 2459650 (feat: v4)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requestBatteryExemption(this)
requestInstallPermission(this)
requestStoragePermission(this)
<<<<<<< HEAD
=======
authManager = AuthManager(this)
>>>>>>> 2459650 (feat: v4)
val appDataPath = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "FireflyGo").absolutePath
val dataDir = File("$appDataPath/data")
if (!dataDir.exists()) dataDir.mkdirs()
val sharedPrefs = getSharedPreferences("AppPrefs", MODE_PRIVATE)
<<<<<<< HEAD
// Lấy thông tin Package
=======
>>>>>>> 2459650 (feat: v4)
val packageInfo = if (Build.VERSION.SDK_INT >= 33) {
packageManager.getPackageInfo(packageName, android.content.pm.PackageManager.PackageInfoFlags.of(0))
} else {
@@ -172,15 +154,6 @@ class MainActivity : ComponentActivity() {
val appVersion = AppVersion(latestVersion, changelog, apkUrl)
<<<<<<< HEAD
enableEdgeToEdge()
setContent {
FireflyPsAndoridTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Box(modifier = Modifier.fillMaxSize()) {
ServerControlScreen(appDataPath, dataDir, appVersion, Modifier.padding(innerPadding))
AutoUpdateDialog(onDismiss = {}, appVersion, dataDir, true)
=======
handleDeepLink(intent)
enableEdgeToEdge()
@@ -223,7 +196,6 @@ class MainActivity : ComponentActivity() {
if (showScamWarning) {
ScamWarningDialog(onDismiss = { showScamWarning = false })
}
>>>>>>> 2459650 (feat: v4)
}
}
}
@@ -231,8 +203,6 @@ class MainActivity : ComponentActivity() {
}
<<<<<<< HEAD
=======
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleDeepLink(intent)
@@ -257,7 +227,6 @@ class MainActivity : ComponentActivity() {
}
}
>>>>>>> 2459650 (feat: v4)
}
@SuppressLint("BatteryLife")
@@ -304,10 +273,7 @@ fun requestStoragePermission(context: Context) {
}
}
}
<<<<<<< HEAD
=======
>>>>>>> 2459650 (feat: v4)
fun copyRawToFile(context: Context, targetDir: File, override: Boolean = false): Boolean {
val files = listOf(
"data-in-game.json" to "data-in-game.json",
@@ -364,10 +330,9 @@ fun removeFile(targetDir: File, fileName: String): Boolean {
}
<<<<<<< HEAD
@SuppressLint("ImplicitSamInstance")
@Composable
fun ServerControlScreen(appDataPath: String, dataDir: File, appVersion: AppVersion, modifier: Modifier = Modifier) {
fun ServerControlScreen(appDataPath: String, dataDir: File, appVersion: AppVersion, authManager: AuthManager, modifier: Modifier = Modifier) {
val context = LocalContext.current
val isRunning = GolangServerService.isRunning
@@ -1110,7 +1075,8 @@ fun ActionButtons(
}
}
}
=======
}
@Composable
fun Modifier.bounceClick(
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
@@ -1132,5 +1098,4 @@ fun Modifier.bounceClick(
indication = null,
onClick = onClick
)
>>>>>>> 2459650 (feat: v4)
}
@@ -1,4 +1,3 @@
<<<<<<< HEAD
<?xml version="1.0" encoding="utf-8"?>
<vector
android:height="108dp"
@@ -73,79 +72,3 @@
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
</vector>
=======
<?xml version="1.0" encoding="utf-8"?>
<vector
android:height="108dp"
android:width="108dp"
android:viewportHeight="108"
android:viewportWidth="108"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z"/>
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
</vector>
>>>>>>> 2459650 (feat: v4)
@@ -1,12 +1,5 @@
<<<<<<< HEAD
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
=======
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
>>>>>>> 2459650 (feat: v4)
</adaptive-icon>
@@ -1,12 +1,5 @@
<<<<<<< HEAD
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
=======
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
>>>>>>> 2459650 (feat: v4)
</adaptive-icon>
-3
View File
@@ -1,7 +1,5 @@
<resources>
<string name="app_name">Firefly Go</string>
<<<<<<< HEAD
=======
<string name="android_edition">Android Edition</string>
<string name="sign_in">Sign In</string>
<string name="server_running">Server is running</string>
@@ -56,5 +54,4 @@
<string name="auto_scroll">Auto-Scroll</string>
<string name="clear">Clear</string>
<string name="close">Close</string>
>>>>>>> 2459650 (feat: v4)
</resources>
-6
View File
@@ -1,9 +1,3 @@
<<<<<<< HEAD
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="downloads" path="Download/"/>
</paths>
=======
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="downloads" path="Download/"/>
</paths>
>>>>>>> 2459650 (feat: v4)
-9
View File
@@ -1,15 +1,6 @@
<<<<<<< HEAD
#Wed Oct 08 15:20:16 ICT 2025
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
=======
#Wed Oct 08 15:20:16 ICT 2025
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
>>>>>>> 2459650 (feat: v4)