Skip to content

Commit 12d20b4

Browse files
committed
Quick settings tile to toggle the service #235
1 parent ecaa49e commit 12d20b4

File tree

6 files changed

+86
-113
lines changed

6 files changed

+86
-113
lines changed

app/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ android {
4141
else -> 0
4242
}
4343

44-
val vCode = 400
44+
val vCode = 403
4545
versionCode = vCode - singleAbiNum
46-
versionName = "2.1.6"
46+
versionName = "2.1.7"
4747

4848
ndk {
4949
//noinspection ChromeOsAbiSupport

app/src/main/AndroidManifest.xml

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@
9191
<application
9292
android:name=".MainApp"
9393
android:allowBackup="true"
94-
android:enableOnBackInvokedCallback="true"
9594
android:banner="@mipmap/ic_launcher"
95+
android:enableOnBackInvokedCallback="true"
9696
android:icon="@mipmap/ic_launcher"
9797
android:label="@string/app_name"
9898
android:largeHeap="true"
@@ -123,15 +123,17 @@
123123
<intent-filter>
124124
<action android:name="android.intent.action.VIEW" />
125125
<category android:name="android.intent.category.DEFAULT" />
126+
126127
<data android:scheme="content" />
127128
<data android:scheme="file" />
128129
<data android:mimeType="text/*" />
129130
</intent-filter>
130-
131+
131132
<!-- Support for PDF files -->
132133
<intent-filter>
133134
<action android:name="android.intent.action.VIEW" />
134135
<category android:name="android.intent.category.DEFAULT" />
136+
135137
<data android:scheme="content" />
136138
<data android:scheme="file" />
137139
<data android:mimeType="application/pdf" />
@@ -186,22 +188,16 @@
186188
</service>
187189

188190

189-
190-
<!-- <service-->
191-
<!-- android:exported="true"-->
192-
<!-- android:name=".services.QSTileService"-->
193-
<!-- android:icon="@drawable/ic_app_icon"-->
194-
<!-- android:label="@string/app_name"-->
195-
<!-- android:foregroundServiceType="specialUse"-->
196-
<!-- android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"-->
197-
<!-- android:process=":RunPlainServiceDaemon">-->
198-
<!-- <intent-filter>-->
199-
<!-- <action android:name="android.service.quicksettings.action.QS_TILE" />-->
200-
<!-- </intent-filter>-->
201-
<!-- <property-->
202-
<!-- android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"-->
203-
<!-- android:value="tile" />-->
204-
<!-- </service>-->
191+
<service
192+
android:name=".services.QSTileService"
193+
android:exported="true"
194+
android:icon="@drawable/app_icon"
195+
android:label="@string/app_name"
196+
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
197+
<intent-filter>
198+
<action android:name="android.service.quicksettings.action.QS_TILE" />
199+
</intent-filter>
200+
</service>
205201

206202
<receiver
207203
android:name=".receivers.ServiceStopBroadcastReceiver"

app/src/main/java/com/ismartcoding/plain/enums/QSTileServiceAction.kt

Lines changed: 0 additions & 25 deletions
This file was deleted.
Lines changed: 60 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,22 @@
11
package com.ismartcoding.plain.services
22

3-
4-
import android.annotation.SuppressLint
5-
import android.content.BroadcastReceiver
6-
import android.content.Context
73
import android.content.Intent
8-
import android.content.IntentFilter
94
import android.graphics.drawable.Icon
105
import android.service.quicksettings.Tile
116
import android.service.quicksettings.TileService
12-
import com.ismartcoding.lib.channel.sendEvent
7+
import com.ismartcoding.lib.channel.receiveEventHandler
138
import com.ismartcoding.lib.helpers.CoroutinesHelper.coIO
14-
import com.ismartcoding.lib.isTPlus
15-
import com.ismartcoding.plain.BuildConfig
16-
import com.ismartcoding.plain.Constants
9+
import com.ismartcoding.lib.logcat.LogCat
1710
import com.ismartcoding.plain.R
18-
import com.ismartcoding.plain.enums.QSTileServiceAction
19-
import com.ismartcoding.plain.events.StartHttpServerEvent
11+
import com.ismartcoding.plain.TempData
12+
import com.ismartcoding.plain.enums.HttpServerState
13+
import com.ismartcoding.plain.events.HttpServerStateChangedEvent
2014
import com.ismartcoding.plain.preferences.WebPreference
2115
import com.ismartcoding.plain.web.HttpServerManager
22-
import java.lang.ref.SoftReference
2316

2417
class QSTileService : TileService() {
18+
private var httpServerStateListener: ((HttpServerState) -> Unit)? = null
19+
2520
fun setState(state: Int) {
2621
if (state == Tile.STATE_INACTIVE) {
2722
qsTile?.state = Tile.STATE_INACTIVE
@@ -36,86 +31,85 @@ class QSTileService : TileService() {
3631
qsTile?.updateTile()
3732
}
3833

39-
@SuppressLint("UnspecifiedRegisterReceiverFlag")
4034
override fun onStartListening() {
4135
super.onStartListening()
42-
setState(Tile.STATE_INACTIVE)
43-
mMsgReceive = ReceiveMessageHandler(this)
44-
if (isTPlus()) {
45-
registerReceiver(mMsgReceive, IntentFilter(Constants.BROADCAST_ACTION_ACTIVITY), Context.RECEIVER_EXPORTED)
46-
} else {
47-
registerReceiver(mMsgReceive, IntentFilter(Constants.BROADCAST_ACTION_ACTIVITY))
36+
37+
// Register HTTP server state listener
38+
httpServerStateListener = { state ->
39+
when (state) {
40+
HttpServerState.ON -> setState(Tile.STATE_ACTIVE)
41+
HttpServerState.OFF -> setState(Tile.STATE_INACTIVE)
42+
HttpServerState.STARTING -> setState(Tile.STATE_INACTIVE)
43+
HttpServerState.STOPPING -> setState(Tile.STATE_INACTIVE)
44+
HttpServerState.ERROR -> setState(Tile.STATE_INACTIVE)
45+
}
4846
}
4947

50-
sendMsg(this, Constants.BROADCAST_ACTION_SERVICE, QSTileServiceAction.MSG_REGISTER_CLIENT.value, "")
48+
// Listen for HTTP server state changes
49+
receiveEventHandler<HttpServerStateChangedEvent> { event ->
50+
httpServerStateListener?.invoke(event.state)
51+
}
52+
53+
// Check current server state
54+
coIO {
55+
try {
56+
// First check if webEnabled is true in TempData
57+
if (TempData.webEnabled) {
58+
val checkResult = HttpServerManager.checkServerAsync()
59+
if (checkResult.websocket && checkResult.http) {
60+
setState(Tile.STATE_ACTIVE)
61+
} else {
62+
// Service should be running but isn't responding
63+
LogCat.d("Web service enabled but not responding, setting inactive state")
64+
setState(Tile.STATE_INACTIVE)
65+
}
66+
} else {
67+
setState(Tile.STATE_INACTIVE)
68+
}
69+
} catch (e: Exception) {
70+
LogCat.e("Failed to check server state: ${e.message}")
71+
setState(Tile.STATE_INACTIVE)
72+
}
73+
}
5174
}
5275

5376
override fun onStopListening() {
5477
super.onStopListening()
5578

56-
unregisterReceiver(mMsgReceive)
57-
mMsgReceive = null
79+
// Unregister HTTP server state listener
80+
httpServerStateListener = null
5881
}
5982

6083
override fun onClick() {
6184
super.onClick()
6285
when (qsTile.state) {
6386
Tile.STATE_INACTIVE -> {
64-
coIO {
65-
WebPreference.putAsync(this@QSTileService, true)
66-
sendEvent(StartHttpServerEvent())
87+
// Start the service directly
88+
qsTile?.state = Tile.STATE_UNAVAILABLE
89+
qsTile?.updateTile()
90+
91+
// Launch the app with unlockAndRun
92+
unlockAndRun {
93+
val intent = Intent(this, Class.forName("com.ismartcoding.plain.ui.MainActivity"))
94+
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
95+
intent.putExtra("start_web_service", true)
96+
startActivity(intent)
6797
}
6898
}
6999

70100
Tile.STATE_ACTIVE -> {
101+
// Stop service
102+
qsTile?.state = Tile.STATE_UNAVAILABLE
103+
qsTile?.updateTile()
104+
71105
coIO {
72106
WebPreference.putAsync(this@QSTileService, false)
73107
HttpServerManager.stopServiceAsync(this@QSTileService)
108+
setState(Tile.STATE_INACTIVE)
74109
}
75110
}
76111
}
77112
}
78113

79-
private var mMsgReceive: BroadcastReceiver? = null
80-
81-
private class ReceiveMessageHandler(context: QSTileService) : BroadcastReceiver() {
82-
internal var mReference: SoftReference<QSTileService> = SoftReference(context)
83-
override fun onReceive(ctx: Context?, intent: Intent?) {
84-
val context = mReference.get()
85-
when (intent?.getIntExtra("key", 0)) {
86-
QSTileServiceAction.MSG_STATE_RUNNING.value -> {
87-
context?.setState(Tile.STATE_ACTIVE)
88-
}
89-
90-
QSTileServiceAction.MSG_STATE_NOT_RUNNING.value -> {
91-
context?.setState(Tile.STATE_INACTIVE)
92-
}
93-
94-
QSTileServiceAction.MSG_STATE_START_SUCCESS.value -> {
95-
context?.setState(Tile.STATE_ACTIVE)
96-
}
97114

98-
QSTileServiceAction.MSG_STATE_START_FAILURE.value -> {
99-
context?.setState(Tile.STATE_INACTIVE)
100-
}
101-
102-
QSTileServiceAction.MSG_STATE_STOP_SUCCESS.value -> {
103-
context?.setState(Tile.STATE_INACTIVE)
104-
}
105-
}
106-
}
107-
}
108-
109-
private fun sendMsg(ctx: Context, action: String, what: Int, content: String) {
110-
try {
111-
val intent = Intent()
112-
intent.action = action
113-
intent.`package` = BuildConfig.APPLICATION_ID
114-
intent.putExtra("key", what)
115-
intent.putExtra("content", content)
116-
ctx.sendBroadcast(intent)
117-
} catch (e: Exception) {
118-
e.printStackTrace()
119-
}
120-
}
121115
}

app/src/main/java/com/ismartcoding/plain/ui/MainActivity.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import com.ismartcoding.plain.events.PickFileEvent
6464
import com.ismartcoding.plain.events.PickFileResultEvent
6565
import com.ismartcoding.plain.events.RequestPermissionsEvent
6666
import com.ismartcoding.plain.events.RestartAppEvent
67+
import com.ismartcoding.plain.events.StartHttpServerEvent
6768
import com.ismartcoding.plain.events.StartScreenMirrorEvent
6869
import com.ismartcoding.plain.events.WebSocketEvent
6970
import com.ismartcoding.plain.events.WindowFocusChangedEvent
@@ -549,6 +550,13 @@ class MainActivity : AppCompatActivity() {
549550
}
550551

551552
private fun handleIntent(intent: Intent) {
553+
if (intent.getBooleanExtra("start_web_service", false)) {
554+
coIO {
555+
WebPreference.putAsync(this@MainActivity, true)
556+
sendEvent(StartHttpServerEvent())
557+
}
558+
}
559+
552560
if (intent.action == Intent.ACTION_VIEW) {
553561
val uri = intent.data
554562
if (uri != null) {

app/src/main/java/com/ismartcoding/plain/web/HttpServerManager.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ object HttpServerManager {
100100
suspend fun checkServerAsync(): HttpServerCheckResult {
101101
var websocket = false
102102
var http = false
103-
var retry = 3
103+
var retry = 2
104104
val client = HttpClientManager.httpClient()
105105
while (retry-- > 0) {
106106
try {
@@ -113,7 +113,7 @@ object HttpServerManager {
113113
}
114114
retry = 0
115115
} catch (ex: Exception) {
116-
delay(1000)
116+
delay(300)
117117
ex.printStackTrace()
118118
LogCat.e(ex.toString())
119119
}

0 commit comments

Comments
 (0)