feat: add background keep-alive service and related setting functions
This commit is contained in:
@@ -81,7 +81,7 @@ dependencies {
|
|||||||
debugImplementation(libs.androidx.ui.test.manifest)
|
debugImplementation(libs.androidx.ui.test.manifest)
|
||||||
implementation("org.json:json:20231013")
|
implementation("org.json:json:20231013")
|
||||||
implementation("androidx.compose.material:material-icons-extended:1.5.4")
|
implementation("androidx.compose.material:material-icons-extended:1.5.4")
|
||||||
|
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||||
|
|
||||||
implementation("org.osmdroid:osmdroid-android:6.1.16")
|
implementation("org.osmdroid:osmdroid-android:6.1.16")
|
||||||
implementation("org.osmdroid:osmdroid-mapsforge:6.1.16")
|
implementation("org.osmdroid:osmdroid-mapsforge:6.1.16")
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
|
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
|
||||||
|
|
||||||
@@ -22,14 +24,14 @@
|
|||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.LBJReceiver"
|
android:theme="@style/Theme.LBJConsole"
|
||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true"
|
||||||
tools:targetApi="31">
|
tools:targetApi="31">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/Theme.LBJReceiver">
|
android:theme="@style/Theme.LBJConsole">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
@@ -37,6 +39,19 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".SettingsActivity"
|
||||||
|
android:exported="false"
|
||||||
|
android:label="Settings"
|
||||||
|
android:parentActivityName=".MainActivity"
|
||||||
|
android:theme="@style/Theme.LBJConsole" />
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".BackgroundService"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="false"
|
||||||
|
android:foregroundServiceType="dataSync" />
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
android:authorities="${applicationId}.provider"
|
android:authorities="${applicationId}.provider"
|
||||||
|
|||||||
@@ -437,6 +437,7 @@ class BLEClient(private val context: Context) : BluetoothGattCallback() {
|
|||||||
try {
|
try {
|
||||||
gatt.close()
|
gatt.close()
|
||||||
bluetoothGatt = null
|
bluetoothGatt = null
|
||||||
|
bluetoothLeScanner = null
|
||||||
|
|
||||||
deviceAddress?.let { address ->
|
deviceAddress?.let { address ->
|
||||||
if (autoReconnect) {
|
if (autoReconnect) {
|
||||||
@@ -819,6 +820,7 @@ class BLEClient(private val context: Context) : BluetoothGattCallback() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
bluetoothGatt = null
|
bluetoothGatt = null
|
||||||
|
bluetoothLeScanner = null
|
||||||
deviceAddress = null
|
deviceAddress = null
|
||||||
connectionAttempts = 0
|
connectionAttempts = 0
|
||||||
|
|
||||||
|
|||||||
123
app/src/main/java/org/noxylva/lbjconsole/BackgroundService.kt
Normal file
123
app/src/main/java/org/noxylva/lbjconsole/BackgroundService.kt
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
package org.noxylva.lbjconsole
|
||||||
|
|
||||||
|
import android.app.Notification
|
||||||
|
import android.app.NotificationChannel
|
||||||
|
import android.app.NotificationManager
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.app.Service
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.IBinder
|
||||||
|
import android.os.PowerManager
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
|
|
||||||
|
class BackgroundService : Service() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val NOTIFICATION_ID = 1001
|
||||||
|
private const val CHANNEL_ID = "background_service_channel"
|
||||||
|
private const val CHANNEL_NAME = "Background Service"
|
||||||
|
|
||||||
|
fun startService(context: Context) {
|
||||||
|
try {
|
||||||
|
val intent = Intent(context, BackgroundService::class.java)
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
context.startForegroundService(intent)
|
||||||
|
} else {
|
||||||
|
context.startService(intent)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// Service start failed, ignore silently
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stopService(context: Context) {
|
||||||
|
val intent = Intent(context, BackgroundService::class.java)
|
||||||
|
context.stopService(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var wakeLock: PowerManager.WakeLock? = null
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
createNotificationChannel()
|
||||||
|
acquireWakeLock()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
try {
|
||||||
|
val notification = createNotification()
|
||||||
|
startForeground(NOTIFICATION_ID, notification)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
|
stopSelf()
|
||||||
|
return START_NOT_STICKY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return START_STICKY
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
releaseWakeLock()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBind(intent: Intent?): IBinder? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createNotificationChannel() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
val channel = NotificationChannel(
|
||||||
|
CHANNEL_ID,
|
||||||
|
CHANNEL_NAME,
|
||||||
|
NotificationManager.IMPORTANCE_LOW
|
||||||
|
).apply {
|
||||||
|
description = "Keep app running in background"
|
||||||
|
setShowBadge(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
notificationManager.createNotificationChannel(channel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createNotification(): Notification {
|
||||||
|
val intent = Intent(this, MainActivity::class.java)
|
||||||
|
val pendingIntent = PendingIntent.getActivity(
|
||||||
|
this,
|
||||||
|
0,
|
||||||
|
intent,
|
||||||
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||||
|
)
|
||||||
|
|
||||||
|
return NotificationCompat.Builder(this, CHANNEL_ID)
|
||||||
|
.setContentTitle("LBJ Console")
|
||||||
|
.setContentText("Running in background")
|
||||||
|
.setSmallIcon(R.drawable.ic_launcher_foreground)
|
||||||
|
.setContentIntent(pendingIntent)
|
||||||
|
.setOngoing(true)
|
||||||
|
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun acquireWakeLock() {
|
||||||
|
val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||||
|
wakeLock = powerManager.newWakeLock(
|
||||||
|
PowerManager.PARTIAL_WAKE_LOCK,
|
||||||
|
"LBJConsole::BackgroundWakeLock"
|
||||||
|
)
|
||||||
|
wakeLock?.acquire()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun releaseWakeLock() {
|
||||||
|
wakeLock?.let {
|
||||||
|
if (it.isHeld) {
|
||||||
|
it.release()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wakeLock = null
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -47,6 +47,7 @@ import androidx.compose.ui.text.style.TextAlign
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.window.Dialog
|
import androidx.compose.ui.window.Dialog
|
||||||
import androidx.compose.ui.window.DialogProperties
|
import androidx.compose.ui.window.DialogProperties
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
@@ -61,7 +62,7 @@ import org.noxylva.lbjconsole.ui.screens.HistoryScreen
|
|||||||
import org.noxylva.lbjconsole.ui.screens.MapScreen
|
import org.noxylva.lbjconsole.ui.screens.MapScreen
|
||||||
import org.noxylva.lbjconsole.ui.screens.SettingsScreen
|
import org.noxylva.lbjconsole.ui.screens.SettingsScreen
|
||||||
|
|
||||||
import org.noxylva.lbjconsole.ui.theme.LBJReceiverTheme
|
import org.noxylva.lbjconsole.ui.theme.LBJConsoleTheme
|
||||||
import org.noxylva.lbjconsole.util.LocoInfoUtil
|
import org.noxylva.lbjconsole.util.LocoInfoUtil
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
@@ -256,7 +257,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
tileDownloadThreads = 4
|
tileDownloadThreads = 4
|
||||||
tileFileSystemThreads = 4
|
tileFileSystemThreads = 4
|
||||||
|
|
||||||
setUserAgentValue("LBJReceiver/1.0")
|
setUserAgentValue("LBJConsole/1.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.d(TAG, "OSM cache configured")
|
Log.d(TAG, "OSM cache configured")
|
||||||
@@ -266,13 +267,17 @@ class MainActivity : ComponentActivity() {
|
|||||||
|
|
||||||
saveSettings()
|
saveSettings()
|
||||||
|
|
||||||
|
if (SettingsActivity.isBackgroundServiceEnabled(this)) {
|
||||||
|
BackgroundService.startService(this)
|
||||||
|
}
|
||||||
|
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
|
|
||||||
WindowCompat.getInsetsController(window, window.decorView).apply {
|
WindowCompat.getInsetsController(window, window.decorView).apply {
|
||||||
isAppearanceLightStatusBars = false
|
isAppearanceLightStatusBars = false
|
||||||
}
|
}
|
||||||
setContent {
|
setContent {
|
||||||
LBJReceiverTheme {
|
LBJConsoleTheme {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
Surface(modifier = Modifier.fillMaxSize()) {
|
Surface(modifier = Modifier.fillMaxSize()) {
|
||||||
@@ -406,7 +411,11 @@ class MainActivity : ComponentActivity() {
|
|||||||
Log.d(TAG, "Applied settings deviceName=${settingsDeviceName}")
|
Log.d(TAG, "Applied settings deviceName=${settingsDeviceName}")
|
||||||
},
|
},
|
||||||
appVersion = getAppVersion(),
|
appVersion = getAppVersion(),
|
||||||
locoInfoUtil = locoInfoUtil
|
locoInfoUtil = locoInfoUtil,
|
||||||
|
onOpenSettings = {
|
||||||
|
val intent = Intent(this@MainActivity, SettingsActivity::class.java)
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (showConnectionDialog) {
|
if (showConnectionDialog) {
|
||||||
@@ -879,7 +888,9 @@ fun MainContent(
|
|||||||
mapCenterPosition: Pair<Double, Double>?,
|
mapCenterPosition: Pair<Double, Double>?,
|
||||||
mapZoomLevel: Double,
|
mapZoomLevel: Double,
|
||||||
mapRailwayLayerVisible: Boolean,
|
mapRailwayLayerVisible: Boolean,
|
||||||
onMapStateChange: (Pair<Double, Double>?, Double, Boolean) -> Unit
|
onMapStateChange: (Pair<Double, Double>?, Double, Boolean) -> Unit,
|
||||||
|
|
||||||
|
onOpenSettings: () -> Unit
|
||||||
) {
|
) {
|
||||||
val statusColor = if (isConnected) Color(0xFF4CAF50) else Color(0xFFFF5722)
|
val statusColor = if (isConnected) Color(0xFF4CAF50) else Color(0xFFFF5722)
|
||||||
|
|
||||||
|
|||||||
63
app/src/main/java/org/noxylva/lbjconsole/SettingsActivity.kt
Normal file
63
app/src/main/java/org/noxylva/lbjconsole/SettingsActivity.kt
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package org.noxylva.lbjconsole
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.widget.Switch
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
|
||||||
|
class SettingsActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val PREFS_NAME = "lbj_console_settings"
|
||||||
|
private const val KEY_BACKGROUND_SERVICE = "background_service_enabled"
|
||||||
|
|
||||||
|
fun isBackgroundServiceEnabled(context: Context): Boolean {
|
||||||
|
val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||||
|
return prefs.getBoolean(KEY_BACKGROUND_SERVICE, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setBackgroundServiceEnabled(context: Context, enabled: Boolean) {
|
||||||
|
val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||||
|
prefs.edit().putBoolean(KEY_BACKGROUND_SERVICE, enabled).apply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var backgroundServiceSwitch: Switch
|
||||||
|
private lateinit var prefs: SharedPreferences
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_settings)
|
||||||
|
|
||||||
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
|
supportActionBar?.title = "Settings"
|
||||||
|
|
||||||
|
prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||||
|
|
||||||
|
initViews()
|
||||||
|
setupListeners()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initViews() {
|
||||||
|
backgroundServiceSwitch = findViewById(R.id.switch_background_service)
|
||||||
|
backgroundServiceSwitch.isChecked = isBackgroundServiceEnabled(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupListeners() {
|
||||||
|
backgroundServiceSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||||
|
setBackgroundServiceEnabled(this, isChecked)
|
||||||
|
|
||||||
|
if (isChecked) {
|
||||||
|
BackgroundService.startService(this)
|
||||||
|
} else {
|
||||||
|
BackgroundService.stopService(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSupportNavigateUp(): Boolean {
|
||||||
|
onBackPressed()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import androidx.compose.runtime.*
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
@@ -17,6 +18,8 @@ import androidx.compose.ui.unit.dp
|
|||||||
import org.noxylva.lbjconsole.model.MergeSettings
|
import org.noxylva.lbjconsole.model.MergeSettings
|
||||||
import org.noxylva.lbjconsole.model.GroupBy
|
import org.noxylva.lbjconsole.model.GroupBy
|
||||||
import org.noxylva.lbjconsole.model.TimeWindow
|
import org.noxylva.lbjconsole.model.TimeWindow
|
||||||
|
import org.noxylva.lbjconsole.SettingsActivity
|
||||||
|
import org.noxylva.lbjconsole.BackgroundService
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@@ -164,6 +167,72 @@ fun SettingsScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Card(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
colors = CardDefaults.cardColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f)
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(16.dp)
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(20.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Settings,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colorScheme.primary
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
"应用设置",
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val context = LocalContext.current
|
||||||
|
var backgroundServiceEnabled by remember {
|
||||||
|
mutableStateOf(SettingsActivity.isBackgroundServiceEnabled(context))
|
||||||
|
}
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Column {
|
||||||
|
Text(
|
||||||
|
"后台保活服务",
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
fontWeight = FontWeight.Medium
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
"保持应用在后台运行",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Switch(
|
||||||
|
checked = backgroundServiceEnabled,
|
||||||
|
onCheckedChange = { enabled ->
|
||||||
|
backgroundServiceEnabled = enabled
|
||||||
|
SettingsActivity.setBackgroundServiceEnabled(context, enabled)
|
||||||
|
|
||||||
|
if (enabled) {
|
||||||
|
BackgroundService.startService(context)
|
||||||
|
} else {
|
||||||
|
BackgroundService.stopService(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Card(
|
Card(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
colors = CardDefaults.cardColors(
|
colors = CardDefaults.cardColors(
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ private val LightColorScheme = lightColorScheme(
|
|||||||
)
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LBJReceiverTheme(
|
fun LBJConsoleTheme(
|
||||||
darkTheme: Boolean = true,
|
darkTheme: Boolean = true,
|
||||||
|
|
||||||
dynamicColor: Boolean = true,
|
dynamicColor: Boolean = true,
|
||||||
|
|||||||
55
app/src/main/res/layout/activity_settings.xml
Normal file
55
app/src/main/res/layout/activity_settings.xml
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
android:clickable="true">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Background Service"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Keep app running in background"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textColor="@android:color/darker_gray"
|
||||||
|
android:layout_marginTop="4dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
android:id="@+id/switch_background_service"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="@android:color/darker_gray"
|
||||||
|
android:layout_marginHorizontal="16dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<style name="Theme.LBJReceiver" parent="android:Theme.Material.Light.NoActionBar" />
|
<style name="Theme.LBJConsole" parent="android:Theme.Material.Light.NoActionBar" />
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user