better error handling for server start: show toast
This commit is contained in:
@@ -62,9 +62,13 @@
|
|||||||
<receiver
|
<receiver
|
||||||
android:name=".service.BootReceiver"
|
android:name=".service.BootReceiver"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="true">
|
android:exported="true"
|
||||||
|
android:directBootAware="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
|
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
|
||||||
|
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
|
||||||
|
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,11 @@ import sh.sar.textpipe.server.routes.webUIRoutes
|
|||||||
import sh.sar.textpipe.sim.SimManager
|
import sh.sar.textpipe.sim.SimManager
|
||||||
import java.net.ServerSocket
|
import java.net.ServerSocket
|
||||||
|
|
||||||
|
sealed class ServerStartResult {
|
||||||
|
data object Success : ServerStartResult()
|
||||||
|
data class Error(val message: String) : ServerStartResult()
|
||||||
|
}
|
||||||
|
|
||||||
class TextpipeServer(
|
class TextpipeServer(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val smsRepository: SmsRepository,
|
private val smsRepository: SmsRepository,
|
||||||
@@ -39,7 +44,7 @@ class TextpipeServer(
|
|||||||
@Volatile
|
@Volatile
|
||||||
private var lastError: Throwable? = null
|
private var lastError: Throwable? = null
|
||||||
|
|
||||||
suspend fun start(port: Int): Boolean {
|
suspend fun start(port: Int): ServerStartResult {
|
||||||
// Stop any existing server first
|
// Stop any existing server first
|
||||||
stop()
|
stop()
|
||||||
|
|
||||||
@@ -53,7 +58,7 @@ class TextpipeServer(
|
|||||||
delay(1000)
|
delay(1000)
|
||||||
if (!isPortAvailable(port)) {
|
if (!isPortAvailable(port)) {
|
||||||
Log.e(TAG, "Port $port still not available after waiting")
|
Log.e(TAG, "Port $port still not available after waiting")
|
||||||
return false
|
return ServerStartResult.Error("Port $port is already in use. Try a different port or wait a moment.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +87,7 @@ class TextpipeServer(
|
|||||||
Log.e(TAG, "Server failed to start", lastError)
|
Log.e(TAG, "Server failed to start", lastError)
|
||||||
server?.stop(100, 100)
|
server?.stop(100, 100)
|
||||||
server = null
|
server = null
|
||||||
return false
|
return ServerStartResult.Error("Server error: ${lastError?.message ?: "Unknown error"}")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify server is actually running by checking the port again
|
// Verify server is actually running by checking the port again
|
||||||
@@ -91,16 +96,16 @@ class TextpipeServer(
|
|||||||
Log.e(TAG, "Server didn't bind to port $port")
|
Log.e(TAG, "Server didn't bind to port $port")
|
||||||
server?.stop(100, 100)
|
server?.stop(100, 100)
|
||||||
server = null
|
server = null
|
||||||
return false
|
return ServerStartResult.Error("Server failed to bind to port $port")
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i(TAG, "Server started on port $port")
|
Log.i(TAG, "Server started on port $port")
|
||||||
true
|
ServerStartResult.Success
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Failed to start server on port $port", e)
|
Log.e(TAG, "Failed to start server on port $port", e)
|
||||||
server?.stop(100, 100)
|
server?.stop(100, 100)
|
||||||
server = null
|
server = null
|
||||||
false
|
ServerStartResult.Error("Failed to start: ${e.message ?: "Unknown error"}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,17 @@ package sh.sar.textpipe.service
|
|||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.util.Log
|
||||||
|
|
||||||
class BootReceiver : BroadcastReceiver() {
|
class BootReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private const val TAG = "BootReceiver"
|
||||||
private const val PREFS_NAME = "textpipe_settings"
|
private const val PREFS_NAME = "textpipe_settings"
|
||||||
private const val KEY_AUTO_START = "auto_start"
|
private const val KEY_AUTO_START = "auto_start"
|
||||||
|
private const val START_DELAY_MS = 5000L // Wait 5 seconds after boot
|
||||||
|
|
||||||
fun isAutoStartEnabled(context: Context): Boolean {
|
fun isAutoStartEnabled(context: Context): Boolean {
|
||||||
val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||||
@@ -22,10 +27,28 @@ class BootReceiver : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
if (intent.action != Intent.ACTION_BOOT_COMPLETED) return
|
val action = intent.action
|
||||||
|
if (action != Intent.ACTION_BOOT_COMPLETED &&
|
||||||
|
action != Intent.ACTION_LOCKED_BOOT_COMPLETED &&
|
||||||
|
action != "android.intent.action.QUICKBOOT_POWERON" &&
|
||||||
|
action != "com.htc.intent.action.QUICKBOOT_POWERON") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.i(TAG, "Boot completed received: $action")
|
||||||
|
|
||||||
if (isAutoStartEnabled(context)) {
|
if (isAutoStartEnabled(context)) {
|
||||||
TextpipeService.start(context)
|
// Delay start slightly to let system settle
|
||||||
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
|
Log.i(TAG, "Starting TextpipeService after boot")
|
||||||
|
try {
|
||||||
|
TextpipeService.start(context.applicationContext)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Failed to start service on boot", e)
|
||||||
|
}
|
||||||
|
}, START_DELAY_MS)
|
||||||
|
} else {
|
||||||
|
Log.i(TAG, "Auto-start is disabled, not starting service")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,11 @@ import android.app.Service
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.os.Handler
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
import android.os.Looper
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -23,6 +26,7 @@ import sh.sar.textpipe.MainActivity
|
|||||||
import sh.sar.textpipe.TextpipeApplication
|
import sh.sar.textpipe.TextpipeApplication
|
||||||
import sh.sar.textpipe.data.repository.SmsRepository
|
import sh.sar.textpipe.data.repository.SmsRepository
|
||||||
import sh.sar.textpipe.root.RootManager
|
import sh.sar.textpipe.root.RootManager
|
||||||
|
import sh.sar.textpipe.server.ServerStartResult
|
||||||
import sh.sar.textpipe.server.TextpipeServer
|
import sh.sar.textpipe.server.TextpipeServer
|
||||||
|
|
||||||
class TextpipeService : Service() {
|
class TextpipeService : Service() {
|
||||||
@@ -133,15 +137,24 @@ class TextpipeService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start HTTP server
|
// Start HTTP server
|
||||||
val started = textpipeServer?.start(port) ?: false
|
when (val result = textpipeServer?.start(port)) {
|
||||||
if (started) {
|
is ServerStartResult.Success -> {
|
||||||
_isRunning.value = true
|
_isRunning.value = true
|
||||||
val displayPort = if (redirectPort > 0) redirectPort else port
|
val displayPort = if (redirectPort > 0) redirectPort else port
|
||||||
updateNotification("Running on port $displayPort")
|
updateNotification("Running on port $displayPort")
|
||||||
Log.i(TAG, "Server started successfully on port $port")
|
showToast("Server started on port $displayPort")
|
||||||
} else {
|
Log.i(TAG, "Server started successfully on port $port")
|
||||||
updateNotification("Failed to start on port $port")
|
}
|
||||||
Log.e(TAG, "Failed to start server on port $port")
|
is ServerStartResult.Error -> {
|
||||||
|
updateNotification("Error: ${result.message}")
|
||||||
|
showToast(result.message)
|
||||||
|
Log.e(TAG, "Failed to start server: ${result.message}")
|
||||||
|
}
|
||||||
|
null -> {
|
||||||
|
updateNotification("Error: Server not initialized")
|
||||||
|
showToast("Server not initialized")
|
||||||
|
Log.e(TAG, "Server is null, cannot start")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,4 +230,10 @@ class TextpipeService : Service() {
|
|||||||
val notificationManager = getSystemService(NotificationManager::class.java)
|
val notificationManager = getSystemService(NotificationManager::class.java)
|
||||||
notificationManager.notify(NOTIFICATION_ID, notification)
|
notificationManager.notify(NOTIFICATION_ID, notification)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showToast(message: String) {
|
||||||
|
Handler(Looper.getMainLooper()).post {
|
||||||
|
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user