mirror of
https://github.com/dovecoteescapee/ByeDPIAndroid.git
synced 2024-12-22 06:15:44 +00:00
Add support for Quick Tile
This commit is contained in:
parent
48f5edd337
commit
d43e991ae8
@ -23,6 +23,7 @@
|
||||
android:launchMode="singleInstance">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
@ -55,6 +56,18 @@
|
||||
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
||||
android:value="proxy" />
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".services.QuickTileService"
|
||||
android:icon="@drawable/ic_notification"
|
||||
android:label="@string/app_name"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
|
||||
<intent-filter>
|
||||
<action
|
||||
android:name="android.service.quicksettings.action.QS_TILE"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
</application>
|
||||
|
||||
</manifest>
|
@ -15,8 +15,6 @@ import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import io.github.dovecoteescapee.byedpi.data.START_ACTION
|
||||
import io.github.dovecoteescapee.byedpi.data.STOP_ACTION
|
||||
import io.github.dovecoteescapee.byedpi.R
|
||||
import io.github.dovecoteescapee.byedpi.data.AppStatus
|
||||
import io.github.dovecoteescapee.byedpi.data.FAILED_BROADCAST
|
||||
@ -27,8 +25,7 @@ import io.github.dovecoteescapee.byedpi.data.STOPPED_BROADCAST
|
||||
import io.github.dovecoteescapee.byedpi.data.Sender
|
||||
import io.github.dovecoteescapee.byedpi.fragments.SettingsFragment
|
||||
import io.github.dovecoteescapee.byedpi.databinding.ActivityMainBinding
|
||||
import io.github.dovecoteescapee.byedpi.services.ByeDpiProxyService
|
||||
import io.github.dovecoteescapee.byedpi.services.ByeDpiVpnService
|
||||
import io.github.dovecoteescapee.byedpi.services.ServiceManager
|
||||
import io.github.dovecoteescapee.byedpi.services.appStatus
|
||||
import io.github.dovecoteescapee.byedpi.utility.getPreferences
|
||||
import io.github.dovecoteescapee.byedpi.utility.mode
|
||||
@ -57,7 +54,7 @@ class MainActivity : AppCompatActivity() {
|
||||
private val vpnRegister =
|
||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
if (it.resultCode == RESULT_OK) {
|
||||
startVpn()
|
||||
ServiceManager.start(this, Mode.VPN)
|
||||
} else {
|
||||
Toast.makeText(this, R.string.vpn_permission_denied, Toast.LENGTH_SHORT).show()
|
||||
updateStatus()
|
||||
@ -212,48 +209,16 @@ class MainActivity : AppCompatActivity() {
|
||||
if (intentPrepare != null) {
|
||||
vpnRegister.launch(intentPrepare)
|
||||
} else {
|
||||
startVpn()
|
||||
ServiceManager.start(this, Mode.VPN)
|
||||
}
|
||||
}
|
||||
|
||||
Mode.Proxy -> startProxy()
|
||||
Mode.Proxy -> ServiceManager.start(this, Mode.Proxy)
|
||||
}
|
||||
}
|
||||
|
||||
private fun startVpn() {
|
||||
Log.i(TAG, "Starting VPN")
|
||||
val intent = Intent(this, ByeDpiVpnService::class.java)
|
||||
intent.action = START_ACTION
|
||||
startService(intent)
|
||||
}
|
||||
|
||||
private fun startProxy() {
|
||||
Log.i(TAG, "Starting proxy")
|
||||
val intent = Intent(this, ByeDpiProxyService::class.java)
|
||||
intent.action = START_ACTION
|
||||
startService(intent)
|
||||
}
|
||||
|
||||
private fun stop() {
|
||||
val (_, mode) = appStatus
|
||||
when (mode) {
|
||||
Mode.VPN -> stopVpn()
|
||||
Mode.Proxy -> stopProxy()
|
||||
}
|
||||
}
|
||||
|
||||
private fun stopVpn() {
|
||||
Log.i(TAG, "Stopping VPN")
|
||||
val intent = Intent(this, ByeDpiVpnService::class.java)
|
||||
intent.action = STOP_ACTION
|
||||
startService(intent)
|
||||
}
|
||||
|
||||
private fun stopProxy() {
|
||||
Log.i(TAG, "Stopping proxy")
|
||||
val intent = Intent(this, ByeDpiProxyService::class.java)
|
||||
intent.action = STOP_ACTION
|
||||
startService(intent)
|
||||
ServiceManager.stop(this)
|
||||
}
|
||||
|
||||
private fun updateStatus() {
|
||||
|
@ -0,0 +1,133 @@
|
||||
package io.github.dovecoteescapee.byedpi.services
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.net.VpnService
|
||||
import android.os.Build
|
||||
import android.service.quicksettings.Tile
|
||||
import android.service.quicksettings.TileService
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.service.quicksettings.PendingIntentActivityWrapper
|
||||
import androidx.core.service.quicksettings.TileServiceCompat
|
||||
import io.github.dovecoteescapee.byedpi.R
|
||||
import io.github.dovecoteescapee.byedpi.activities.MainActivity
|
||||
import io.github.dovecoteescapee.byedpi.data.AppStatus
|
||||
import io.github.dovecoteescapee.byedpi.data.FAILED_BROADCAST
|
||||
import io.github.dovecoteescapee.byedpi.data.Mode
|
||||
import io.github.dovecoteescapee.byedpi.data.SENDER
|
||||
import io.github.dovecoteescapee.byedpi.data.STARTED_BROADCAST
|
||||
import io.github.dovecoteescapee.byedpi.data.STOPPED_BROADCAST
|
||||
import io.github.dovecoteescapee.byedpi.data.Sender
|
||||
import io.github.dovecoteescapee.byedpi.utility.getPreferences
|
||||
import io.github.dovecoteescapee.byedpi.utility.mode
|
||||
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.N)
|
||||
class QuickTileService : TileService() {
|
||||
|
||||
companion object {
|
||||
private val TAG: String = QuickTileService::class.java.simpleName
|
||||
}
|
||||
|
||||
private val receiver: BroadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val senderOrd = intent.getIntExtra(SENDER, -1)
|
||||
val sender = Sender.entries.getOrNull(senderOrd)
|
||||
if (sender == null) {
|
||||
Log.w(TAG, "Received intent with unknown sender: $senderOrd")
|
||||
return
|
||||
}
|
||||
|
||||
when (val action = intent.action) {
|
||||
STARTED_BROADCAST,
|
||||
STOPPED_BROADCAST -> updateStatus()
|
||||
|
||||
FAILED_BROADCAST -> {
|
||||
Toast.makeText(
|
||||
context,
|
||||
getString(R.string.failed_to_start, sender.name),
|
||||
Toast.LENGTH_SHORT,
|
||||
).show()
|
||||
updateStatus()
|
||||
}
|
||||
|
||||
else -> Log.w(TAG, "Unknown action: $action")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartListening() {
|
||||
updateStatus()
|
||||
ContextCompat.registerReceiver(
|
||||
this,
|
||||
receiver,
|
||||
IntentFilter().apply {
|
||||
addAction(STARTED_BROADCAST)
|
||||
addAction(STOPPED_BROADCAST)
|
||||
addAction(FAILED_BROADCAST)
|
||||
},
|
||||
ContextCompat.RECEIVER_EXPORTED,
|
||||
)
|
||||
}
|
||||
|
||||
override fun onStopListening() {
|
||||
unregisterReceiver(receiver)
|
||||
}
|
||||
|
||||
private fun launchActivity() {
|
||||
TileServiceCompat.startActivityAndCollapse(
|
||||
this, PendingIntentActivityWrapper(
|
||||
this, 0, Intent(this, MainActivity::class.java),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT, false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onClick() {
|
||||
if (qsTile.state == Tile.STATE_UNAVAILABLE) {
|
||||
return
|
||||
}
|
||||
|
||||
unlockAndRun(this::handleClick)
|
||||
}
|
||||
|
||||
private fun setState(newState: Int) {
|
||||
qsTile.apply {
|
||||
state = newState
|
||||
updateTile()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateStatus() {
|
||||
val (status) = appStatus
|
||||
setState(if (status == AppStatus.Halted) Tile.STATE_INACTIVE else Tile.STATE_ACTIVE)
|
||||
}
|
||||
|
||||
private fun handleClick() {
|
||||
setState(Tile.STATE_ACTIVE)
|
||||
setState(Tile.STATE_UNAVAILABLE)
|
||||
|
||||
val (status) = appStatus
|
||||
when (status) {
|
||||
AppStatus.Halted -> {
|
||||
val mode = getPreferences(this).mode()
|
||||
|
||||
if (mode == Mode.VPN && VpnService.prepare(this) != null) {
|
||||
updateStatus()
|
||||
launchActivity()
|
||||
return
|
||||
}
|
||||
|
||||
ServiceManager.start(this, mode)
|
||||
}
|
||||
|
||||
AppStatus.Running -> ServiceManager.stop(this)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package io.github.dovecoteescapee.byedpi.services
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import io.github.dovecoteescapee.byedpi.data.Mode
|
||||
import io.github.dovecoteescapee.byedpi.data.START_ACTION
|
||||
import io.github.dovecoteescapee.byedpi.data.STOP_ACTION
|
||||
|
||||
object ServiceManager {
|
||||
private val TAG: String = ServiceManager::class.java.simpleName
|
||||
|
||||
fun start(context: Context, mode: Mode) {
|
||||
when (mode) {
|
||||
Mode.VPN -> {
|
||||
Log.i(TAG, "Starting VPN")
|
||||
val intent = Intent(context, ByeDpiVpnService::class.java)
|
||||
intent.action = START_ACTION
|
||||
context.startService(intent)
|
||||
}
|
||||
|
||||
Mode.Proxy -> {
|
||||
Log.i(TAG, "Starting proxy")
|
||||
val intent = Intent(context, ByeDpiProxyService::class.java)
|
||||
intent.action = START_ACTION
|
||||
context.startService(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun stop(context: Context) {
|
||||
val (_, mode) = appStatus
|
||||
when (mode) {
|
||||
Mode.VPN -> {
|
||||
Log.i(TAG, "Stopping VPN")
|
||||
val intent = Intent(context, ByeDpiVpnService::class.java)
|
||||
intent.action = STOP_ACTION
|
||||
context.startService(intent)
|
||||
}
|
||||
|
||||
Mode.Proxy -> {
|
||||
Log.i(TAG, "Stopping proxy")
|
||||
val intent = Intent(context, ByeDpiProxyService::class.java)
|
||||
intent.action = STOP_ACTION
|
||||
context.startService(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -38,7 +38,7 @@ fun createConnectionNotification(
|
||||
service: Class<*>,
|
||||
): Notification =
|
||||
NotificationCompat.Builder(context, channelId)
|
||||
.setSmallIcon(R.mipmap.ic_launcher)
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setSilent(true)
|
||||
.setContentTitle(context.getString(title))
|
||||
.setContentText(context.getString(content))
|
||||
|
BIN
app/src/main/res/drawable-hdpi/ic_notification.png
Normal file
BIN
app/src/main/res/drawable-hdpi/ic_notification.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 820 B |
BIN
app/src/main/res/drawable-mdpi/ic_notification.png
Normal file
BIN
app/src/main/res/drawable-mdpi/ic_notification.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 486 B |
BIN
app/src/main/res/drawable-xhdpi/ic_notification.png
Normal file
BIN
app/src/main/res/drawable-xhdpi/ic_notification.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_notification.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/ic_notification.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_notification.png
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/ic_notification.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
Loading…
Reference in New Issue
Block a user