mirror of
https://github.com/yuga-hashimoto/openclaw-assistant.git
synced 2026-08-14 08:15:42 +00:00
* Add missing Android node command families (parity gap) - Implement Notifications, System, Photos, Contacts, Calendar, and Motion command families. - Add OpenClawNotificationListenerService and NotificationManager for notification support. - Implement robust runtime permission checks and structured error handling in all handlers. - Wire new handlers into NodeRuntime, InvokeDispatcher, and ConnectionManager. - Conditionally advertise capabilities to the gateway based on granted permissions. - Add unit tests for command routing and handler logic. - Update AndroidManifest.xml with necessary permissions and service declarations. Co-authored-by: yuga-hashimoto <74749461+yuga-hashimoto@users.noreply.github.com> * Refine Android node command families based on PR feedback - Implement actual Notification actions (dismiss, open) using NotificationListenerService. - Correct permission gating for Notifications (use Listener Service check instead of POST_NOTIFICATIONS). - Add runtime permission check for system.notify on Android 13+. - Improve Calendar event insertion by querying for a writable calendar instead of hardcoding ID 1. - Update capability advertisement in ConnectionManager to reflect true availability. - Enhance PhotosHandler and MotionHandler with more complete implementations. - Update unit tests to match refined permission and action logic. Co-authored-by: yuga-hashimoto <74749461+yuga-hashimoto@users.noreply.github.com> * Finalize Android node command families with refined notification support - Implement dismiss/open notification actions using NotificationListenerService. - Return NOT_IMPLEMENTED for reply notification action as requested. - Fix permission gating for notifications (use listener service status). - Add runtime permission check for system notifications on Android 13+. - Improve calendar event creation with dynamic writable calendar selection. - Refine capability advertising in ConnectionManager. - Clean up unused imports and duplicated logic. - Update unit tests to match refined behavior. Co-authored-by: yuga-hashimoto <74749461+yuga-hashimoto@users.noreply.github.com> * fix: address review issues in node command families PR - MotionHandler: add close() to unregister SensorEventListener on disconnect - NodeRuntime: call motionHandler.close() in disconnect() for proper cleanup - OpenClawNotificationListenerService: add @Volatile to companion manager field - SystemHandlerTest: replace unconditional SDK_INT branch with asserting tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: add on-demand permission requests to new node command handlers Contacts, Calendar, Photos, and Motion handlers now use PermissionRequester to show the system permission dialog when a command is first invoked, matching the existing SMS/Camera handler pattern. - ContactsHandler, CalendarHandler, PhotosHandler, MotionHandler: add attachPermissionRequester() + ensureXPermission() suspend helpers, convert handle methods to suspend fun - PermissionRequester: add human-readable labels for new permissions - NodeRuntime: expose attachPermissionRequester() delegating to all handlers - MainActivity: wire permissionRequester to new handlers on startup - InvokeDispatcherTest: update every -> coEvery for suspend handler mocks Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: guide user to notification listener settings via dialog When notifications.list or notifications.actions is invoked without notification access, show an AlertDialog explaining the requirement and open ACTION_NOTIFICATION_LISTENER_SETTINGS on confirmation. - PermissionRequester: add requestNotificationAccess() suspend fun - NotificationsHandler: add PermissionRequester wiring, make handle methods suspend, call requestNotificationAccess() before error return - NodeRuntime.attachPermissionRequester: include notificationsHandler Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * add funding --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
63 lines
2.5 KiB
Kotlin
63 lines
2.5 KiB
Kotlin
package com.openclaw.assistant.node
|
|
|
|
import android.Manifest
|
|
import android.app.NotificationChannel
|
|
import android.app.NotificationManager
|
|
import android.content.Context
|
|
import android.content.pm.PackageManager
|
|
import android.os.Build
|
|
import androidx.core.app.NotificationCompat
|
|
import androidx.core.content.ContextCompat
|
|
import com.openclaw.assistant.R
|
|
import com.openclaw.assistant.gateway.GatewaySession
|
|
import kotlinx.serialization.json.Json
|
|
import kotlinx.serialization.json.JsonPrimitive
|
|
import kotlinx.serialization.json.jsonObject
|
|
|
|
class SystemHandler(private val appContext: Context) {
|
|
|
|
private val json = Json { ignoreUnknownKeys = true }
|
|
|
|
fun handleNotify(paramsJson: String?): GatewaySession.InvokeResult {
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
if (ContextCompat.checkSelfPermission(appContext, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
|
return GatewaySession.InvokeResult.error("PERMISSION_REQUIRED", "POST_NOTIFICATIONS permission required")
|
|
}
|
|
}
|
|
|
|
val params = paramsJson?.let {
|
|
try {
|
|
json.parseToJsonElement(it).jsonObject
|
|
} catch (e: Exception) {
|
|
null
|
|
}
|
|
} ?: return GatewaySession.InvokeResult.error("INVALID_REQUEST", "Expected JSON object")
|
|
|
|
val title = (params["title"] as? JsonPrimitive)?.content ?: "OpenClaw Assistant"
|
|
val message = (params["message"] as? JsonPrimitive)?.content ?: ""
|
|
|
|
if (message.isEmpty()) {
|
|
return GatewaySession.InvokeResult.error("INVALID_REQUEST", "Message is required")
|
|
}
|
|
|
|
val notificationManager = appContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
val channelId = "openclaw_system"
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
val channel = NotificationChannel(channelId, "OpenClaw System Notifications", NotificationManager.IMPORTANCE_DEFAULT)
|
|
notificationManager.createNotificationChannel(channel)
|
|
}
|
|
|
|
val notification = NotificationCompat.Builder(appContext, channelId)
|
|
.setSmallIcon(R.mipmap.ic_launcher)
|
|
.setContentTitle(title)
|
|
.setContentText(message)
|
|
.setAutoCancel(true)
|
|
.build()
|
|
|
|
notificationManager.notify(System.currentTimeMillis().toInt(), notification)
|
|
|
|
return GatewaySession.InvokeResult.ok("""{"ok":true}""")
|
|
}
|
|
}
|