@@ -472,6 +472,7 @@
|
||||
<string name="gesture_handler_open_app_drawer">Open app drawer</string>
|
||||
<string name="gesture_handler_open_app_search">Open app search</string>
|
||||
<string name="gesture_handler_open_search">Open search</string>
|
||||
<string name="gesture_handler_open_assistant">Open assistant</string>
|
||||
|
||||
<string name="pick_app_for_gesture">Pick app</string>
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import app.lawnchair.gestures.handlers.OpenAppDrawerGestureHandler
|
||||
import app.lawnchair.gestures.handlers.OpenAppGestureHandler
|
||||
import app.lawnchair.gestures.handlers.OpenAppSearchGestureHandler
|
||||
import app.lawnchair.gestures.handlers.OpenAppTarget
|
||||
import app.lawnchair.gestures.handlers.OpenAssistantHandler
|
||||
import app.lawnchair.gestures.handlers.OpenNotificationsHandler
|
||||
import app.lawnchair.gestures.handlers.OpenSearchGestureHandler
|
||||
import app.lawnchair.gestures.handlers.RecentsGestureHandler
|
||||
@@ -61,6 +62,10 @@ sealed class GestureHandlerConfig {
|
||||
@SerialName("openSearch")
|
||||
data object OpenSearch : Simple(R.string.gesture_handler_open_search, ::OpenSearchGestureHandler)
|
||||
|
||||
@Serializable
|
||||
@SerialName("openAssistant")
|
||||
data object OpenAssistant : Simple(R.string.gesture_handler_open_assistant, ::OpenAssistantHandler)
|
||||
|
||||
@Serializable
|
||||
@SerialName("openApp")
|
||||
data class OpenApp(val appName: String, val target: OpenAppTarget) : GestureHandlerConfig() {
|
||||
|
||||
@@ -30,6 +30,7 @@ sealed class GestureHandlerOption(
|
||||
data object OpenAppDrawer : Simple(GestureHandlerConfig.OpenAppDrawer)
|
||||
data object OpenAppSearch : Simple(GestureHandlerConfig.OpenAppSearch)
|
||||
data object OpenSearch : Simple(GestureHandlerConfig.OpenSearch)
|
||||
data object OpenAssistant : Simple(GestureHandlerConfig.OpenAssistant)
|
||||
|
||||
data object OpenApp : GestureHandlerOption(
|
||||
R.string.gesture_handler_open_app_option,
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package app.lawnchair.gestures.handlers
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import app.lawnchair.LawnchairLauncher
|
||||
|
||||
class OpenAssistantHandler(context: Context) : GestureHandler(context) {
|
||||
|
||||
override suspend fun onTrigger(launcher: LawnchairLauncher) {
|
||||
try {
|
||||
val component = getCurrentlySelectedDefaultAssistant(context)
|
||||
Log.d(TAG, "Detected assistant: $component")
|
||||
|
||||
when {
|
||||
component == null -> noValidAssistantFound()
|
||||
isActivity(component) -> launchIntent(Intent(Intent.ACTION_ASSIST).setComponent(component))
|
||||
isService(component) -> launchIntent(Intent(Intent.ACTION_VOICE_COMMAND))
|
||||
isInstalled(component.packageName) -> launchIntent(context.packageManager.getLaunchIntentForPackage(component.packageName))
|
||||
else -> noValidAssistantFound()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error launching assistant", e)
|
||||
noValidAssistantFound()
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchIntent(intent: Intent?) {
|
||||
intent?.apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
runCatching { context.startActivity(this) }
|
||||
.onFailure { Log.e(TAG, "Failed to launch intent: $intent", it) }
|
||||
} ?: Log.e(TAG, "Intent is null, cannot launch.")
|
||||
}
|
||||
|
||||
private fun noValidAssistantFound() {
|
||||
Log.e(TAG, "No valid assistant found, opening voice input settings.")
|
||||
launchIntent(Intent(Settings.ACTION_VOICE_INPUT_SETTINGS))
|
||||
}
|
||||
|
||||
private fun getCurrentlySelectedDefaultAssistant(context: Context): ComponentName? = Settings.Secure.getString(context.contentResolver, "assistant")
|
||||
?.takeIf { it.isNotEmpty() }
|
||||
?.let(ComponentName::unflattenFromString)
|
||||
?: context.packageManager.resolveActivity(Intent(Intent.ACTION_ASSIST), PackageManager.MATCH_DEFAULT_ONLY)
|
||||
?.activityInfo?.let { ComponentName(it.packageName, it.name) }
|
||||
|
||||
private fun isActivity(component: ComponentName) = context.packageManager.queryIntentActivities(Intent().setComponent(component), PackageManager.MATCH_DEFAULT_ONLY).isNotEmpty()
|
||||
|
||||
private fun isService(component: ComponentName) = context.packageManager.getInstalledPackages(PackageManager.GET_SERVICES)
|
||||
.any { it.packageName == component.packageName && it.services?.any { service -> service.name == component.className } == true }
|
||||
|
||||
private fun isInstalled(packageName: String) = runCatching {
|
||||
context.packageManager.getPackageInfo(packageName, 0)
|
||||
true
|
||||
}.getOrDefault(false)
|
||||
|
||||
companion object {
|
||||
private const val TAG = "OpenAssistantHandler"
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ val options = listOf(
|
||||
GestureHandlerOption.OpenAppSearch,
|
||||
GestureHandlerOption.OpenSearch,
|
||||
GestureHandlerOption.OpenApp,
|
||||
GestureHandlerOption.OpenAssistant,
|
||||
)
|
||||
|
||||
@Composable
|
||||
|
||||
Reference in New Issue
Block a user