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