diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 95fb9c0dd..8ab0c4519 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1231,6 +1231,24 @@
android:value="android.service.quicksettings.CATEGORY_UTILITIES" />
+
+
+
+
+
+
+
+
+
= listOf("WRITE_SECURE_SETTINGS")
+ override val isConfigurable: Boolean = true
+ }
+
@Keep
enum class SettingsTable {
@SerializedName("SYSTEM")
diff --git a/app/src/main/java/com/sameerasw/essentials/domain/genai/AutomationSuggestion.kt b/app/src/main/java/com/sameerasw/essentials/domain/genai/AutomationSuggestion.kt
index 836baa5b0..ef8226ec8 100644
--- a/app/src/main/java/com/sameerasw/essentials/domain/genai/AutomationSuggestion.kt
+++ b/app/src/main/java/com/sameerasw/essentials/domain/genai/AutomationSuggestion.kt
@@ -105,5 +105,8 @@ data class AutomationSuggestion(
val smartPixelsEnabled: Boolean? = null,
@Guide(description = "Dim wallpaper amount (0.0 to 1.0) for DimWallpaper action")
- val dimWallpaperAmount: Float? = null
+ val dimWallpaperAmount: Float? = null,
+
+ @Guide(description = "Select keyboard from the list to switch")
+ val keyboard: String? = null,
)
diff --git a/app/src/main/java/com/sameerasw/essentials/services/automation/executors/CombinedActionExecutor.kt b/app/src/main/java/com/sameerasw/essentials/services/automation/executors/CombinedActionExecutor.kt
index fc937c867..38c189771 100644
--- a/app/src/main/java/com/sameerasw/essentials/services/automation/executors/CombinedActionExecutor.kt
+++ b/app/src/main/java/com/sameerasw/essentials/services/automation/executors/CombinedActionExecutor.kt
@@ -19,10 +19,12 @@ import android.os.Build
import android.provider.Settings
import android.view.KeyEvent
import android.widget.Toast
+import com.sameerasw.essentials.R
import com.sameerasw.essentials.domain.HapticFeedbackType
import com.sameerasw.essentials.domain.diy.Action
import com.sameerasw.essentials.services.tiles.ScreenOffAccessibilityService
import com.sameerasw.essentials.utils.DeviceLockUtils
+import com.sameerasw.essentials.utils.PermissionUtils
import com.sameerasw.essentials.utils.ShellUtils
import com.sameerasw.essentials.utils.performHapticFeedback
import rikka.shizuku.ShizukuBinderWrapper
@@ -652,6 +654,19 @@ object CombinedActionExecutor {
com.sameerasw.essentials.utils.FreezeManager.unfreezeApp(context, pkg)
}
}
+
+ is Action.Keyboard -> {
+ try {
+ if (PermissionUtils.canWriteSecureSettings(context)) {
+ Settings.Secure.putString(context.contentResolver, Settings.Secure.DEFAULT_INPUT_METHOD, action.inputMethodId)
+ return@withContext
+ }
+ Toast.makeText(context, R.string.diy_set_keyboard_permission_required, Toast.LENGTH_SHORT).show()
+ } catch (e: Exception) {
+ Toast.makeText(context, "Keyboard Switching Failed: ${e.message ?: ""}", Toast.LENGTH_SHORT).show()
+ }
+ }
+
is Action.CustomSettings -> {
val resolver = context.contentResolver
for (entry in action.entries) {
diff --git a/app/src/main/java/com/sameerasw/essentials/services/tiles/QsTileRegistry.kt b/app/src/main/java/com/sameerasw/essentials/services/tiles/QsTileRegistry.kt
index 78b59e87d..fe0d57a1b 100644
--- a/app/src/main/java/com/sameerasw/essentials/services/tiles/QsTileRegistry.kt
+++ b/app/src/main/java/com/sameerasw/essentials/services/tiles/QsTileRegistry.kt
@@ -159,7 +159,17 @@ object QsTileRegistry {
R.string.tile_essentials_on_display,
R.drawable.rounded_live_tv_24,
EssentialsOnDisplayTileService::class.java
- )
+ ),
+ QsTileEntry(
+ R.string.tile_lockdown_mode,
+ R.drawable.rounded_shield_lock_24,
+ LockdownTileService::class.java
+ ),
+ QsTileEntry(
+ R.string.tile_wifi_adb_title_short,
+ R.drawable.wireless_debugging_24,
+ WirelessDebugging::class.java
+ ),
)
private val tilesMapByClassName: Map by lazy {
diff --git a/app/src/main/java/com/sameerasw/essentials/services/tiles/UsbDebuggingTileService.kt b/app/src/main/java/com/sameerasw/essentials/services/tiles/UsbDebuggingTileService.kt
index e49506d50..b9607e84d 100644
--- a/app/src/main/java/com/sameerasw/essentials/services/tiles/UsbDebuggingTileService.kt
+++ b/app/src/main/java/com/sameerasw/essentials/services/tiles/UsbDebuggingTileService.kt
@@ -11,15 +11,15 @@ package com.sameerasw.essentials.services.tiles
import android.content.Intent
import android.graphics.drawable.Icon
-import android.os.Build
import android.provider.Settings
import android.service.quicksettings.Tile
-import androidx.annotation.RequiresApi
+import android.util.Log
+import android.widget.Toast
import com.sameerasw.essentials.FeatureSettingsActivity
import com.sameerasw.essentials.R
+import com.sameerasw.essentials.data.repository.SettingsRepository
import com.sameerasw.essentials.utils.PermissionUtils
-@RequiresApi(Build.VERSION_CODES.N)
class UsbDebuggingTileService : BaseTileService() {
override fun onClick() {
@@ -37,14 +37,7 @@ class UsbDebuggingTileService : BaseTileService() {
override fun getTileLabel(): String = getString(R.string.tile_usb_debugging)
override fun getTileSubtitle(): String {
- val usbOn = isUsbDebuggingEnabled()
- val wifiOn = isWifiDebuggingEnabled()
- return when {
- usbOn && wifiOn -> "USB & WiFi"
- usbOn -> "USB"
- wifiOn -> "WiFi"
- else -> getString(R.string.off)
- }
+ return if (isUsbDebuggingEnabled()) getString(R.string.on) else getString(R.string.off)
}
override fun hasFeaturePermission(): Boolean {
@@ -56,18 +49,11 @@ class UsbDebuggingTileService : BaseTileService() {
}
override fun getTileState(): Int {
- val usbOn = isUsbDebuggingEnabled()
- val wifiOn = isWifiDebuggingEnabled()
- return if (usbOn && wifiOn) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE
+ return if (isUsbDebuggingEnabled()) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE
}
override fun onTileClick() {
- val usbOn = isUsbDebuggingEnabled()
- val wifiOn = isWifiDebuggingEnabled()
-
- val newState = if (usbOn && wifiOn) 0 else 1
- setUsbDebuggingEnabled(newState == 1)
- setWifiDebuggingEnabled(newState == 1)
+ setUsbDebuggingEnabled(!isUsbDebuggingEnabled())
}
private fun isUsbDebuggingEnabled(): Boolean {
@@ -80,25 +66,48 @@ class UsbDebuggingTileService : BaseTileService() {
private fun setUsbDebuggingEnabled(enabled: Boolean) {
try {
- Settings.Global.putInt(contentResolver, Settings.Global.ADB_ENABLED, if (enabled) 1 else 0)
+ if (!enabled) {
+ toggleShizuku(false)
+ }
+ Settings.Global.putInt(
+ contentResolver,
+ Settings.Global.ADB_ENABLED,
+ if (enabled) 1 else 0
+ )
+ if (enabled) {
+ toggleShizuku(true)
+ }
} catch (e: Exception) {
e.printStackTrace()
}
}
- private fun isWifiDebuggingEnabled(): Boolean {
- return try {
- Settings.Global.getInt(contentResolver, "adb_wifi_enabled", 0) == 1
- } catch (e: Exception) {
- false
- }
+ private fun getShizukuToken(): String {
+ return SettingsRepository(this).getShizukuAuthToken()
}
- private fun setWifiDebuggingEnabled(enabled: Boolean) {
- try {
- Settings.Global.putInt(contentResolver, "adb_wifi_enabled", if (enabled) 1 else 0)
- } catch (e: Exception) {
- e.printStackTrace()
+ private fun toggleShizuku(enabled: Boolean) {
+ val token = getShizukuToken()
+ val action =
+ if (enabled) "moe.shizuku.privileged.api.START" else "moe.shizuku.privileged.api.STOP"
+
+ if (token.isEmpty()) {
+ Toast.makeText(
+ this,
+ this.getString(R.string.toast_enter_shizuku_token),
+ Toast.LENGTH_LONG
+ ).show()
+ } else {
+ try {
+ val shizukuIntent = Intent(action).apply {
+ `package` = "moe.shizuku.privileged.api"
+ putExtra("auth", token)
+ addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
+ }
+ this.sendBroadcast(shizukuIntent)
+ } catch (e: Exception) {
+ Log.e("ShizukuActionReceiver", "Failed to restart Shizuku", e)
+ }
}
}
}
diff --git a/app/src/main/java/com/sameerasw/essentials/services/tiles/WirelessDebugging.kt b/app/src/main/java/com/sameerasw/essentials/services/tiles/WirelessDebugging.kt
new file mode 100644
index 000000000..8103180ea
--- /dev/null
+++ b/app/src/main/java/com/sameerasw/essentials/services/tiles/WirelessDebugging.kt
@@ -0,0 +1,69 @@
+package com.sameerasw.essentials.services.tiles
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.graphics.drawable.Icon
+import android.os.Build
+import android.provider.Settings
+import android.service.quicksettings.Tile
+import com.sameerasw.essentials.FeatureSettingsActivity
+import com.sameerasw.essentials.R
+import com.sameerasw.essentials.utils.PermissionUtils
+
+class WirelessDebugging : BaseTileService() {
+ override fun onClick() {
+ if (!hasFeaturePermission()) {
+ val intent = Intent(this, FeatureSettingsActivity::class.java).apply {
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
+ putExtra("feature", "Quick settings tiles")
+ }
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+ startActivityAndCollapse(intent)
+ return
+ }
+ val pendingIntent = PendingIntent.getActivity(
+ this,
+ 0,
+ intent,
+ PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
+ )
+ startActivityAndCollapse(pendingIntent)
+ return
+ }
+ super.onClick()
+ }
+
+ override fun onTileClick() = setWifiDebuggingEnabled(!isWifiDebuggingEnabled())
+
+ override fun getTileLabel() = getString(R.string.tile_wifi_adb_title_short)
+
+ override fun getTileSubtitle(): String {
+ return if (isWifiDebuggingEnabled()) getString(R.string.on) else getString(R.string.off)
+ }
+
+ override fun hasFeaturePermission() = PermissionUtils.canWriteSecureSettings(this)
+
+ override fun getTileIcon(): Icon {
+ return Icon.createWithResource(this, R.drawable.wireless_debugging_24)
+ }
+
+ override fun getTileState(): Int {
+ return if (isWifiDebuggingEnabled()) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE
+ }
+
+ private fun isWifiDebuggingEnabled(): Boolean {
+ return try {
+ Settings.Global.getInt(contentResolver, "adb_wifi_enabled", 0) == 1
+ } catch (e: Exception) {
+ false
+ }
+ }
+
+ private fun setWifiDebuggingEnabled(enabled: Boolean) {
+ try {
+ Settings.Global.putInt(contentResolver, "adb_wifi_enabled", if (enabled) 1 else 0)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/sameerasw/essentials/ui/activities/AutomationEditorActivity.kt b/app/src/main/java/com/sameerasw/essentials/ui/activities/AutomationEditorActivity.kt
index 50ec80554..5968bbe63 100644
--- a/app/src/main/java/com/sameerasw/essentials/ui/activities/AutomationEditorActivity.kt
+++ b/app/src/main/java/com/sameerasw/essentials/ui/activities/AutomationEditorActivity.kt
@@ -12,6 +12,7 @@ package com.sameerasw.essentials.ui.activities
import android.content.Context
import android.content.Intent
import android.os.Bundle
+import android.view.inputmethod.InputMethodInfo
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
@@ -102,6 +103,7 @@ import com.sameerasw.essentials.ui.core.sheets.ScreenOffSettingsSheet
import com.sameerasw.essentials.ui.core.sheets.SingleAppSelectionSheet
import com.sameerasw.essentials.ui.core.sheets.SoundModeSettingsSheet
import com.sameerasw.essentials.ui.core.sheets.WifiNetworkSelectionSheet
+import com.sameerasw.essentials.ui.features.apps.sheets.KeyboardSelectionSheet
import com.sameerasw.essentials.ui.theme.EssentialsTheme
import com.sameerasw.essentials.utils.AppUtil
import com.sameerasw.essentials.utils.HapticUtil
@@ -266,6 +268,8 @@ class AutomationEditorActivity : ComponentActivity() {
var showTimeSettings by remember { mutableStateOf(false) }
var showBluetoothSettings by remember { mutableStateOf(false) }
var showWifiSettings by remember { mutableStateOf(false) }
+ var showSetKeyboardSheet by remember { mutableStateOf(false) }
+ var selectedIme by remember { mutableStateOf(null) }
var showCustomSettingsSettings by remember { mutableStateOf(false) }
var configAction by remember { mutableStateOf(null) } // Generic config action
@@ -298,6 +302,7 @@ class AutomationEditorActivity : ComponentActivity() {
fun isActionConfigured(action: Action?): Boolean = when (action) {
is Action.OpenApp -> action.packageName.isNotBlank()
is Action.CustomSettings -> action.entries.isNotEmpty()
+ is Action.Keyboard -> !action.inputMethodId.isNullOrEmpty()
else -> true
}
@@ -905,7 +910,8 @@ class AutomationEditorActivity : ComponentActivity() {
Action.FreezeApps(),
Action.UnfreezeApps(),
Action.FreezeTag(),
- Action.PinApp
+ Action.PinApp,
+ Action.Keyboard()
)
val systemActions = listOf(
Action.TurnOnFlashlight,
@@ -961,6 +967,13 @@ class AutomationEditorActivity : ComponentActivity() {
) {
actions.forEach { action ->
val resolvedAction = if (currentSelection != null && currentSelection::class == action::class) currentSelection else action
+ val missing = getMissingPermissionsHelper(resolvedAction)
+ fun showPermissionSheet() {
+ permissionKeysToShow = missing
+ permissionFeatureTitle = resolvedAction.title
+ showPermissionSheet = true
+ }
+
EditorActionItem(
title = stringResource(resolvedAction.title),
iconRes = resolvedAction.icon,
@@ -975,14 +988,14 @@ class AutomationEditorActivity : ComponentActivity() {
else selectedOutAction = resolvedAction
}
}
- val missing = getMissingPermissionsHelper(resolvedAction)
- if (missing.isNotEmpty()) {
- permissionKeysToShow = missing
- permissionFeatureTitle = resolvedAction.title
- showPermissionSheet = true
- }
+ if(missing.isNotEmpty()) showPermissionSheet()
},
onSettingsClick = {
+ if(missing.isNotEmpty()) {
+ showPermissionSheet()
+ return@EditorActionItem
+ }
+
configAction = resolvedAction
when (resolvedAction) {
is Action.DimWallpaper -> showDimSettings = true
@@ -1000,6 +1013,10 @@ class AutomationEditorActivity : ComponentActivity() {
temporarySelectedAppsForAction = resolvedAction.packageNames
showFreezeAppsSettings = true
}
+ is Action.Keyboard -> {
+ showSetKeyboardSheet = true
+ selectedIme = resolvedAction.inputMethodId
+ }
is Action.CustomSettings -> showCustomSettingsSettings = true
else -> {}
}
@@ -1285,6 +1302,26 @@ class AutomationEditorActivity : ComponentActivity() {
)
}
+ if (showSetKeyboardSheet && configAction is Action.Keyboard) {
+ KeyboardSelectionSheet(
+ onDismissRequest = { newIme ->
+ showSetKeyboardSheet = false
+ when (automationType) {
+ Automation.Type.TRIGGER -> selectedAction = Action.Keyboard(newIme)
+ Automation.Type.ACTION_SHORTCUT, Automation.Type.PIXEL_SEARCHBAR -> selectedAction =
+ Action.Keyboard(newIme)
+
+ Automation.Type.STATE, Automation.Type.APP -> {
+ if (selectedActionTab == 0) selectedInAction = Action.Keyboard(newIme)
+ else selectedOutAction = Action.Keyboard(newIme)
+ }
+ }
+ configAction = null
+ },
+ selectedIme = (configAction as? Action.Keyboard)?.inputMethodId
+ )
+ }
+
if (showCustomSettingsSettings && configAction is Action.CustomSettings) {
CustomSettingsSheet(
initialAction = configAction as Action.CustomSettings,
diff --git a/app/src/main/java/com/sameerasw/essentials/ui/composables/WelcomeScreen.kt b/app/src/main/java/com/sameerasw/essentials/ui/composables/WelcomeScreen.kt
index f1a5c22f8..96e8e18e0 100644
--- a/app/src/main/java/com/sameerasw/essentials/ui/composables/WelcomeScreen.kt
+++ b/app/src/main/java/com/sameerasw/essentials/ui/composables/WelcomeScreen.kt
@@ -374,12 +374,12 @@ fun WelcomeStepContent(
modifier = Modifier
.clip(RoundedCornerShape(100.dp))
.background(MaterialTheme.colorScheme.primaryContainer)
- .padding(8.dp)
.clickable {
val websiteUrl = "https://sameerasw.com"
val intent = Intent(Intent.ACTION_VIEW, websiteUrl.toUri())
context.startActivity(intent)
- },
+ }
+ .padding(8.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
diff --git a/app/src/main/java/com/sameerasw/essentials/ui/features/apps/sheets/KeyboardSelectionSheet.kt b/app/src/main/java/com/sameerasw/essentials/ui/features/apps/sheets/KeyboardSelectionSheet.kt
new file mode 100644
index 000000000..bb27de6c9
--- /dev/null
+++ b/app/src/main/java/com/sameerasw/essentials/ui/features/apps/sheets/KeyboardSelectionSheet.kt
@@ -0,0 +1,189 @@
+package com.sameerasw.essentials.ui.features.apps.sheets
+
+import android.content.Context
+import android.os.Build
+import android.provider.Settings
+import android.util.Log
+import android.view.inputmethod.InputMethodInfo
+import android.view.inputmethod.InputMethodManager
+import android.widget.Toast
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.ListItem
+import androidx.compose.material3.ListItemDefaults
+import androidx.compose.material3.LoadingIndicator
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.RadioButton
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalView
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.core.graphics.drawable.toBitmap
+import com.sameerasw.essentials.R
+import com.sameerasw.essentials.ui.core.sheets.EssentialsBottomSheet
+import com.sameerasw.essentials.utils.HapticUtil
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+
+@Composable
+fun KeyboardSelectionSheet(
+ onDismissRequest: (ime: String?) -> Unit,
+ selectedIme: String?,
+ context: Context = LocalContext.current
+) {
+ var isLoadingKeyboards by remember { mutableStateOf(true) }
+ var defaultInputMethod by remember { mutableStateOf(null) }
+ var imesList by remember { mutableStateOf>(emptyList()) }
+ val view = LocalView.current
+ val isDeprecated = Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+
+ LaunchedEffect(Unit) {
+ isLoadingKeyboards = true
+ try {
+ val list = withContext(Dispatchers.IO) {
+ val imes =
+ context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+ val defaultIme =
+ if (isDeprecated)
+ imes.currentInputMethodInfo?.id
+ else
+ Settings.Secure.getString(
+ context.contentResolver,
+ Settings.Secure.DEFAULT_INPUT_METHOD
+ )
+ defaultIme to imes
+ }
+ defaultInputMethod = selectedIme ?: (list.first ?: "")
+ imesList = list.second.inputMethodList
+ } catch (e: Exception) {
+ Log.e(
+ "KeyboardSelectionSheet", "Error loading input methods list: ${e.message ?: ""}"
+ )
+ } finally {
+ isLoadingKeyboards = false
+ }
+ }
+
+ EssentialsBottomSheet(
+ onDismissRequest = { onDismissRequest(defaultInputMethod) },
+ ) {
+ Column(
+ modifier = Modifier
+ .padding(start = 16.dp, end = 16.dp, bottom = 16.dp),
+ verticalArrangement = Arrangement.spacedBy(16.dp)
+ ) {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = stringResource(R.string.diy_set_keyboard_sheet_title),
+ style = MaterialTheme.typography.headlineSmall,
+ fontWeight = FontWeight.SemiBold
+ )
+ }
+
+ if (isLoadingKeyboards) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(vertical = 32.dp),
+ horizontalArrangement = Arrangement.Center
+ ) {
+ LoadingIndicator()
+ }
+ } else {
+ LazyColumn(
+ modifier = Modifier
+ .fillMaxWidth()
+ .weight(1f, fill = false)
+ .clip(RoundedCornerShape(24.dp)),
+ verticalArrangement = Arrangement.spacedBy(2.dp)
+ ) {
+ items(imesList, key = { it.id }) { ime ->
+ val isEnabled = ime.serviceInfo.enabled
+ val isSelected = defaultInputMethod == ime.id
+
+ ListItem(
+ checked = isSelected,
+ onCheckedChange = {
+ if (isEnabled) {
+ HapticUtil.performVirtualKeyHaptic(view)
+ defaultInputMethod = ime.id
+ } else {
+ HapticUtil.performVirtualKeyHaptic(view)
+ Toast.makeText(
+ context,
+ R.string.diy_set_keyboard_input_method_disabled,
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+ },
+ onLongClick = null,
+ enabled = isEnabled,
+ modifier = Modifier.fillMaxWidth(),
+ verticalAlignment = Alignment.CenterVertically,
+ leadingContent = {
+ Image(
+ bitmap = ime.loadIcon(context.packageManager).toBitmap()
+ .asImageBitmap(),
+ contentDescription = ime.serviceInfo.name,
+ modifier = Modifier.size(24.dp),
+ contentScale = ContentScale.Fit
+ )
+ },
+ supportingContent = null,
+ trailingContent = {
+ RadioButton(
+ selected = if (isEnabled) isSelected else false,
+ onClick = null,
+ enabled = isEnabled
+ )
+ },
+ colors = ListItemDefaults.colors(
+ containerColor = MaterialTheme.colorScheme.surfaceBright
+ ),
+ contentPadding = androidx.compose.foundation.layout.PaddingValues(
+ horizontal = 16.dp,
+ vertical = 16.dp
+ ),
+ content = {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(4.dp)
+ ) {
+ Text(
+ text = ime.loadLabel(context.packageManager).toString(),
+ style = MaterialTheme.typography.bodyMedium,
+ color = MaterialTheme.colorScheme.onSurface
+ )
+ }
+ }
+ )
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/sameerasw/essentials/ui/features/tiles/QuickSettingsTilesSettingsUI.kt b/app/src/main/java/com/sameerasw/essentials/ui/features/tiles/QuickSettingsTilesSettingsUI.kt
index 5f95d18ce..377025b83 100644
--- a/app/src/main/java/com/sameerasw/essentials/ui/features/tiles/QuickSettingsTilesSettingsUI.kt
+++ b/app/src/main/java/com/sameerasw/essentials/ui/features/tiles/QuickSettingsTilesSettingsUI.kt
@@ -86,6 +86,7 @@ import com.sameerasw.essentials.services.tiles.StayAwakeTileService
import com.sameerasw.essentials.services.tiles.TapToWakeTileService
import com.sameerasw.essentials.services.tiles.UiBlurTileService
import com.sameerasw.essentials.services.tiles.UsbDebuggingTileService
+import com.sameerasw.essentials.services.tiles.WirelessDebugging
import com.sameerasw.essentials.ui.core.sheets.PermissionsBottomSheet
import com.sameerasw.essentials.ui.modifiers.highlight
import com.sameerasw.essentials.utils.DeviceUtils
@@ -383,6 +384,14 @@ fun QuickSettingsTilesSettingsUI(
listOf("ACCESSIBILITY", "NOTIFICATION_LISTENER"),
R.string.feat_essentials_on_display_desc,
R.string.cat_visuals
+ ),
+ QSTileInfo(
+ R.string.tile_wifi_adb_title,
+ R.drawable.wireless_debugging_24,
+ WirelessDebugging::class.java,
+ listOf("WRITE_SECURE_SETTINGS"),
+ R.string.tile_wifi_adb_desc,
+ R.string.cat_utils
)
)
diff --git a/app/src/main/java/com/sameerasw/essentials/viewmodels/DIYViewModel.kt b/app/src/main/java/com/sameerasw/essentials/viewmodels/DIYViewModel.kt
index 9bd3db5e7..bec2f6aa7 100644
--- a/app/src/main/java/com/sameerasw/essentials/viewmodels/DIYViewModel.kt
+++ b/app/src/main/java/com/sameerasw/essentials/viewmodels/DIYViewModel.kt
@@ -226,6 +226,8 @@ class DIYViewModel(application: Application) : AndroidViewModel(application) {
tagIds = suggestion.freezeTagIds
)
+ "Keyboard" -> Action.Keyboard(suggestion.keyboard)
+
else -> null
}
}
diff --git a/app/src/main/res/drawable/wireless_debugging_24.xml b/app/src/main/res/drawable/wireless_debugging_24.xml
new file mode 100644
index 000000000..9616ce22e
--- /dev/null
+++ b/app/src/main/res/drawable/wireless_debugging_24.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f2bf81a53..7b183f502 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -337,7 +337,9 @@
Lockdown
Screen off QS tile
Lock your phone or Lockdown if lockdown mode is turned on.\n\nLockdown mode disables weak unlock methods like face/fingerprint and require pattern or pin securely to unlock your phone.\n\nRequires device admin permission if using lockdown.
-
+ Wireless Debugging
+ Wifi Adb
+ Toggle Wireless Debugging (Wifi Adb) from a QS Tile and from favourite features too.
Disable QS tiles when the device is locked
@@ -1054,6 +1056,11 @@
Setting Key
Value
+ Set Keyboard
+ Select Keyboard
+ Enable input method in settings
+ Grant permission to change your keyboard.
+
Sameera Wijerathna
The all-in-one toolbox for your Pixel and Androids