diff --git a/android/app/src/main/kotlin/app/cogwheel/conduit/ConduitVoiceInteractionSession.kt b/android/app/src/main/kotlin/app/cogwheel/conduit/ConduitVoiceInteractionSession.kt index 9e52f5b..987206b 100644 --- a/android/app/src/main/kotlin/app/cogwheel/conduit/ConduitVoiceInteractionSession.kt +++ b/android/app/src/main/kotlin/app/cogwheel/conduit/ConduitVoiceInteractionSession.kt @@ -9,6 +9,24 @@ import android.app.assist.AssistContent class ConduitVoiceInteractionSession(context: Context) : VoiceInteractionSession(context) { + private var capturedContext: String? = null + private var summarizeButton: android.widget.Button? = null + + override fun onCreateContentView(): android.view.View { + val view = layoutInflater.inflate(app.cogwheel.conduit.R.layout.assistant_overlay, null) + summarizeButton = view.findViewById(app.cogwheel.conduit.R.id.btn_summarize) + summarizeButton?.setOnClickListener { + launchAppWithContext() + } + + val closeButton = view.findViewById(app.cogwheel.conduit.R.id.btn_close) + closeButton?.setOnClickListener { + finish() + } + + return view + } + override fun onHandleAssist( data: Bundle?, structure: AssistStructure?, @@ -18,9 +36,56 @@ class ConduitVoiceInteractionSession(context: Context) : VoiceInteractionSession android.util.Log.d("ConduitVoiceSession", "onHandleAssist called") - // Launch the main activity when the assistant is triggered - val intent = Intent(context, MainActivity::class.java) - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - context.startActivity(intent) + val screenContext = StringBuilder() + structure?.let { + val nodes = it.windowNodeCount + for (i in 0 until nodes) { + val windowNode = it.getWindowNodeAt(i) + traverseNode(windowNode.rootViewNode, screenContext) + } + } + + capturedContext = screenContext.toString() + // Ideally, we could update the UI here to say "Context Ready" + } + + private fun launchAppWithContext() { + try { + android.util.Log.d("ConduitVoiceSession", "Attempting to launch app with context") + val intent = Intent(context, MainActivity::class.java) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + + if (capturedContext != null) { + intent.putExtra("screen_context", capturedContext) + android.util.Log.d("ConduitVoiceSession", "Context attached: ${capturedContext?.take(50)}...") + } else { + android.util.Log.d("ConduitVoiceSession", "No context captured") + } + + context.startActivity(intent) + android.util.Log.d("ConduitVoiceSession", "App launch requested") + finish() // Close the overlay + } catch (e: Exception) { + android.util.Log.e("ConduitVoiceSession", "Failed to launch app", e) + } + } + + private fun traverseNode(node: AssistStructure.ViewNode?, builder: StringBuilder) { + if (node == null) return + + if (node.text != null) { + builder.append(node.text).append("\n") + } + + // Also check content description for accessibility text + if (node.contentDescription != null) { + builder.append(node.contentDescription).append("\n") + } + + for (i in 0 until node.childCount) { + traverseNode(node.getChildAt(i), builder) + } } } diff --git a/android/app/src/main/kotlin/app/cogwheel/conduit/MainActivity.kt b/android/app/src/main/kotlin/app/cogwheel/conduit/MainActivity.kt index edecfcf..4343470 100644 --- a/android/app/src/main/kotlin/app/cogwheel/conduit/MainActivity.kt +++ b/android/app/src/main/kotlin/app/cogwheel/conduit/MainActivity.kt @@ -23,12 +23,32 @@ class MainActivity : FlutterActivity() { windowInsetsController.isAppearanceLightNavigationBars = false } + private val CHANNEL = "app.cogwheel.conduit/assistant" + private var methodChannel: io.flutter.plugin.common.MethodChannel? = null + override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) // Initialize background streaming handler backgroundStreamingHandler = BackgroundStreamingHandler(this) backgroundStreamingHandler.setup(flutterEngine) + + methodChannel = io.flutter.plugin.common.MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL) + + // Check if started with context + handleIntent(intent) + } + + override fun onNewIntent(intent: android.content.Intent) { + super.onNewIntent(intent) + handleIntent(intent) + } + + private fun handleIntent(intent: android.content.Intent) { + val screenContext = intent.getStringExtra("screen_context") + if (screenContext != null) { + methodChannel?.invokeMethod("analyzeScreen", screenContext) + } } override fun onDestroy() { diff --git a/android/app/src/main/res/drawable/rounded_button_bg.xml b/android/app/src/main/res/drawable/rounded_button_bg.xml new file mode 100644 index 0000000..ab7b3f1 --- /dev/null +++ b/android/app/src/main/res/drawable/rounded_button_bg.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/android/app/src/main/res/drawable/rounded_overlay_bg.xml b/android/app/src/main/res/drawable/rounded_overlay_bg.xml new file mode 100644 index 0000000..53dea9a --- /dev/null +++ b/android/app/src/main/res/drawable/rounded_overlay_bg.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/android/app/src/main/res/layout/assistant_overlay.xml b/android/app/src/main/res/layout/assistant_overlay.xml new file mode 100644 index 0000000..32ea604 --- /dev/null +++ b/android/app/src/main/res/layout/assistant_overlay.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + +