diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2d782b4..13a0388 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -103,6 +103,21 @@ android:resource="@xml/accessibility_config" /> + + + + + + + + + (data as? JsonObject)?.get("file_path") + ?.let { (it as? JsonPrimitive)?.content } + } + if (filePath == null) { + postResultNotification("Screenshot failed: no file path") + restoreTile() + return@launch + } + + val analyzeResult = visionAnalyze.execute(buildJsonObject { + put("file_path", filePath) + put("question", "Describe what you see on the screen. What app is open? What is the user looking at?") + }) + + if (analyzeResult.success) { + val analysis = analyzeResult.data?.let { data -> + (data as? JsonObject)?.get("analysis") + ?.let { (it as? JsonPrimitive)?.content } + } ?: "Analysis complete" + postResultNotification(analysis) + } else { + postResultNotification("Analysis failed: ${analyzeResult.error}") + } + } catch (e: Exception) { + Log.e(TAG, "Tile screenshot+explain failed: ${e.message}") + postResultNotification("Error: ${e.message}") + } finally { + restoreTile() + } + } + } + + override fun onDestroy() { + tileScope.cancel() + super.onDestroy() + } + + private fun updateTileState() { + val tile = qsTile ?: return + try { + val agentLoop = getEntryPoint().agentLoop() + when (agentLoop.state.value) { + AgentState.IDLE -> { + tile.state = Tile.STATE_ACTIVE + tile.label = "CellClaw" + } + AgentState.THINKING -> { + tile.state = Tile.STATE_ACTIVE + tile.label = "Thinking..." + } + AgentState.EXECUTING_TOOLS -> { + tile.state = Tile.STATE_ACTIVE + tile.label = "Working..." + } + AgentState.WAITING_APPROVAL -> { + tile.state = Tile.STATE_ACTIVE + tile.label = "Approval" + } + AgentState.PAUSED -> { + tile.state = Tile.STATE_INACTIVE + tile.label = "Paused" + } + AgentState.ERROR -> { + tile.state = Tile.STATE_INACTIVE + tile.label = "Error" + } + } + } catch (e: Exception) { + tile.state = Tile.STATE_INACTIVE + tile.label = "CellClaw" + } + tile.updateTile() + } + + private fun restoreTile() { + try { + updateTileState() + } catch (_: Exception) {} + } + + private fun postResultNotification(text: String) { + val notification = NotificationCompat.Builder(this, CellClawApp.CHANNEL_ALERTS) + .setContentTitle("Screen Analysis") + .setContentText(text) + .setStyle(NotificationCompat.BigTextStyle().bigText(text)) + .setSmallIcon(R.drawable.ic_notification) + .setAutoCancel(true) + .build() + + val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager + manager.notify(TILE_NOTIFICATION_ID, notification) + } + + companion object { + private const val TAG = "CellClawTile" + private const val TILE_NOTIFICATION_ID = 200 + } +} diff --git a/app/src/main/res/drawable/ic_qs_cellclaw.xml b/app/src/main/res/drawable/ic_qs_cellclaw.xml new file mode 100644 index 0000000..6da962c --- /dev/null +++ b/app/src/main/res/drawable/ic_qs_cellclaw.xml @@ -0,0 +1,11 @@ + + + +