Skip to content

ADFA-3645 | Open terminal in adjacent window on large screens#1173

Open
jatezzz wants to merge 2 commits intostagefrom
feat/ADFA-3645-multi-window-terminal
Open

ADFA-3645 | Open terminal in adjacent window on large screens#1173
jatezzz wants to merge 2 commits intostagefrom
feat/ADFA-3645-multi-window-terminal

Conversation

@jatezzz
Copy link
Copy Markdown
Collaborator

@jatezzz jatezzz commented Apr 10, 2026

Description

Added support for launching the terminal in a secondary adjacent window (split-screen) when users are on a tablet or DeX device. This allows users to read their code in the editor and interact with the terminal at the same time. The multi-window intent flags were extracted into a reusable Intent.applyMultiWindowFlags() extension function, which is now applied to terminal actions. Additionally, TerminalActivity was updated to handle onNewIntent so that new terminal sessions are created correctly when the activity is already open.

Details

  • Created IntentExtensions.kt to centralize large screen / multi-window intent flag configurations.
  • Applied multi-window flags to OpenTerminalAction and TerminalSidebarAction.
  • Overrode onNewIntent in TerminalActivity to instantiate a newTermuxSession when the activity is launched again.
document_5100351222519432845.mp4

Ticket

ADFA-3645

Observation

Because the multi-window launch uses Intent.FLAG_ACTIVITY_SINGLE_TOP, TerminalActivity requires the onNewIntent implementation to ensure subsequent terminal open actions correctly initialize new sessions with the provided working directory and session name, rather than just bringing the existing window into focus silently.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 10, 2026

📝 Walkthrough
  • Multi-window terminal support: Terminal can now launch in an adjacent window (split-screen) on large-screen devices (tablets, DeX), allowing the editor and terminal to be visible simultaneously.
  • Centralized intent flag management: Added Intent.applyMultiWindowFlags(context) (common/src/main/java/com/itsaky/androidide/utils/IntentExtensions.kt) to consolidate multi-window/task-related Intent flags.
    • On large-screen-like devices it applies FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_SINGLE_TOP | FLAG_ACTIVITY_LAUNCH_ADJACENT.
    • On smaller devices it preserves the previous behavior by adding FLAG_ACTIVITY_NEW_TASK when the context is not an Activity.
  • Updated terminal launch points to use the new extension:
    • OpenTerminalAction (app/src/main/java/com/itsaky/androidide/actions/main/OpenTerminalAction.kt) applies multi-window flags before starting TerminalActivity.
    • TerminalSidebarAction (app/src/main/java/com/itsaky/androidide/actions/sidebar/TerminalSidebarAction.kt) applies multi-window flags to the intent that includes working-directory, session-name, and failsafe extras.
    • HelpActivity.launch() (common/src/main/java/com/itsaky/androidide/activities/editor/HelpActivity.kt) now uses applyMultiWindowFlags(context) and still sets MULTI_WINDOW_URI for large screens.
  • TerminalActivity re-launch/session handling: termux/termux-app/src/main/java/com/itsaky/androidide/activities/TerminalActivity.kt overrides onNewIntent(Intent?) to setIntent(intent), extract session parameters (working dir, session name, failsafe), and create a new Termux session via TermuxService when available. If the service is not yet connected, parameters are cached (pending*) and onServiceConnected will create/set the session. A helper createAndSetSession(...) centralizes session creation + switching.
  • Misc: Single commit includes a fix addressing a potential race condition with TermuxService and formatting/indentation changes.

Risks & best-practice considerations

  • Complex flag interactions: Combining FLAG_ACTIVITY_SINGLE_TOP, FLAG_ACTIVITY_NEW_TASK, FLAG_ACTIVITY_NEW_DOCUMENT and FLAG_ACTIVITY_LAUNCH_ADJACENT can lead to device/OEM-specific task and back-stack behaviors. Validate on Samsung DeX and multiple tablet builds to confirm split-screen, recent-tasks, and navigation behavior.
  • Service readiness & error handling: onNewIntent/createTermuxSession flow caches pending parameters when TermuxService is unavailable, but there is limited explicit logging or user-visible error handling for session creation failures. Add logging and consider user feedback for failures.
  • Race conditions: The commit mentions a potential race-condition fix for TermuxService; ensure thorough testing of rapid, repeated terminal launches and service connect/disconnect scenarios to confirm the race is resolved.
  • Navigation & task-affinity changes: Applying NEW_TASK/NEW_DOCUMENT alters task affinity and recent-tasks behavior; review UX expectations (Up/back, recent apps) and document intended behavior.
  • Testing matrix required: Validate combinations of Activity vs non-Activity contexts, repeated launches (single-top behavior), launching with different extras (working dir, session name, failsafe), and behavior across OEM customizations and Android versions.

Walkthrough

Centralizes multi-window/task intent-flag logic into Intent.applyMultiWindowFlags(context), updates multiple launch sites to use it, and adds onNewIntent() to TerminalActivity to create or queue Termux sessions from incoming intents.

Changes

Cohort / File(s) Summary
Intent Utilities
common/src/main/java/com/itsaky/androidide/utils/IntentExtensions.kt
Added fun Intent.applyMultiWindowFlags(context: Context): Intent that appends multi-window/task flags based on DeviceFormFactorUtils.getCurrent(context).
Activity Intent Launching
app/src/main/java/com/itsaky/androidide/actions/main/OpenTerminalAction.kt, app/src/main/java/com/itsaky/androidide/actions/sidebar/TerminalSidebarAction.kt, common/src/main/java/com/itsaky/androidide/activities/editor/HelpActivity.kt
Refactored intent creation sites to call applyMultiWindowFlags(context) before startActivity(...), replacing inline flag manipulation at call sites.
Terminal Intent Handling
termux/termux-app/src/main/java/com/itsaky/androidide/activities/TerminalActivity.kt
Added onNewIntent(Intent?) handling that sets the intent, extracts Termux session extras (working dir, session name, failsafe), creates and sets a session immediately if service connected, or caches pending values for processing in onServiceConnected. Introduced createAndSetSession(...) helper.

Sequence Diagram(s)

sequenceDiagram
    participant Activity as Activity Component
    participant Intent as Intent Object
    participant Ext as applyMultiWindowFlags()
    participant DFF as DeviceFormFactorUtils
    participant AM as ActivityManager

    Activity->>Intent: create Intent(context, TargetActivity)
    Activity->>Ext: Intent.applyMultiWindowFlags(context)
    Ext->>DFF: getCurrent(context)
    alt Large-screen-like
        Ext->>Intent: add NEW_TASK, NEW_DOCUMENT, SINGLE_TOP, LAUNCH_ADJACENT
    else Non-large-screen
        Ext->>Intent: add NEW_TASK (if context !is Activity)
    end
    Ext-->>Activity: return modified Intent
    Activity->>AM: startActivity(modified Intent)

    rect rgba(100,150,200,0.5)
        Note over Activity,AM: Centralized multi-window flag application before launch
    end
Loading
sequenceDiagram
    participant System as System/Intent Router
    participant TA as TerminalActivity
    participant TS as TermuxService
    participant Session as TermuxSession

    System->>TA: deliver onNewIntent(intent)
    TA->>TA: setIntent(intent)
    TA->>TA: extract extras (workDir, sessionName, failsafe)
    alt mTermuxService != null
        TA->>TS: createTermuxSession(workDir, sessionName, failsafe)
        TS-->>TA: newSession
        alt newSession != null
            TA->>TA: setCurrentSession(newSession.terminalSession)
        end
    else mTermuxService == null
        TA->>TA: cache pendingWorkDir/pendingSessionName/pendingFailsafe
    end

    rect rgba(150,100,200,0.5)
        Note over TA,TS: Incoming intents can spawn or queue terminal sessions
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Daniel-ADFA
  • jomen-adfa
  • itsaky-adfa

Poem

🐰 I hop through intents with flags in tow,
I tuck new windows where big screens grow.
When a terminal calls with a session name,
I queue or spawn it — ready for the game.
Hooray for sessions — bounce, blink, and go! 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and specifically summarizes the main change: enabling terminal launches in adjacent windows on large screens, which aligns with all major modifications across multiple files.
Description check ✅ Passed The description is well-related to the changeset, detailing the multi-window terminal launch support, the new extension function, affected files, and the onNewIntent implementation rationale.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ADFA-3645-multi-window-terminal

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
termux/termux-app/src/main/java/com/itsaky/androidide/activities/TerminalActivity.kt (1)

51-56: ⚠️ Potential issue | 🟡 Minor

Queue session requests when mTermuxService is temporarily unavailable.

If a relaunch intent arrives while mTermuxService is null, the request is dropped and no session is created. Consider buffering the request and consuming it in onServiceConnected to avoid missed opens in edge cases.

🔧 Proposed fix
 class TerminalActivity : TermuxActivity() {
+  private data class PendingSessionRequest(
+    val workingDir: String?,
+    val sessionName: String?,
+    val isFailsafe: Boolean,
+  )
+
+  private var pendingSessionRequest: PendingSessionRequest? = null
+
   override fun onServiceConnected(componentName: ComponentName?, service: IBinder?) {
     super.onServiceConnected(componentName, service)
+    pendingSessionRequest?.let { req ->
+      pendingSessionRequest = null
+      createAndSelectSession(req.workingDir, req.sessionName, req.isFailsafe)
+    }
     lifecycleScope.launch(Dispatchers.IO) {
       Environment.mkdirIfNotExists(Environment.TMP_DIR)
     }
   }
 
-    override fun onNewIntent(intent: Intent?) {
-        super.onNewIntent(intent)
-        setIntent(intent)
-        if (intent == null) return
+  override fun onNewIntent(intent: Intent?) {
+    super.onNewIntent(intent)
+    if (intent == null) return
+    setIntent(intent)
 
-        val newWorkingDir = intent.getStringExtra(TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY.EXTRA_SESSION_WORKING_DIR)
-        val newSessionName = intent.getStringExtra(TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY.EXTRA_SESSION_NAME)
-        val isFailsafe = intent.getBooleanExtra(TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY.EXTRA_FAILSAFE_SESSION, false)
+    val newWorkingDir =
+      intent.getStringExtra(TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY.EXTRA_SESSION_WORKING_DIR)
+    val newSessionName =
+      intent.getStringExtra(TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY.EXTRA_SESSION_NAME)
+    val isFailsafe =
+      intent.getBooleanExtra(TermuxConstants.TERMUX_APP.TERMUX_ACTIVITY.EXTRA_FAILSAFE_SESSION, false)
 
-        val service = mTermuxService
-        if (service != null) {
-            val newSession = service.createTermuxSession(
-                null,
-                null,
-                null,
-                newWorkingDir,
-                isFailsafe,
-                newSessionName
-            )
+    if (mTermuxService == null) {
+      pendingSessionRequest = PendingSessionRequest(newWorkingDir, newSessionName, isFailsafe)
+      return
+    }
 
-            if (newSession != null) {
-                mTermuxTerminalSessionActivityClient.setCurrentSession(newSession.terminalSession)
-            }
-        }
+    createAndSelectSession(newWorkingDir, newSessionName, isFailsafe)
+  }
+
+  private fun createAndSelectSession(workingDir: String?, sessionName: String?, isFailsafe: Boolean) {
+    val newSession =
+      mTermuxService?.createTermuxSession(null, null, null, workingDir, isFailsafe, sessionName)
+    if (newSession != null) {
+      mTermuxTerminalSessionActivityClient.setCurrentSession(newSession.terminalSession)
     }
+  }
 }

Also applies to: 58-81

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@termux/termux-app/src/main/java/com/itsaky/androidide/activities/TerminalActivity.kt`
around lines 51 - 56, The relaunch requests get dropped when mTermuxService is
null; add a small queue (e.g., pendingRelaunchIntents: MutableList<Intent>) and
update the code path that handles incoming relaunch intents (the method that
currently creates sessions from the Intent—call it
handleRelaunchIntent/processRelaunchIntent) to push the Intent into
pendingRelaunchIntents if mTermuxService == null, otherwise process immediately;
then in onServiceConnected, after mTermuxService is set, drain
pendingRelaunchIntents and call the same session-creation logic for each queued
Intent so no requests are lost.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In
`@termux/termux-app/src/main/java/com/itsaky/androidide/activities/TerminalActivity.kt`:
- Around line 51-56: The relaunch requests get dropped when mTermuxService is
null; add a small queue (e.g., pendingRelaunchIntents: MutableList<Intent>) and
update the code path that handles incoming relaunch intents (the method that
currently creates sessions from the Intent—call it
handleRelaunchIntent/processRelaunchIntent) to push the Intent into
pendingRelaunchIntents if mTermuxService == null, otherwise process immediately;
then in onServiceConnected, after mTermuxService is set, drain
pendingRelaunchIntents and call the same session-creation logic for each queued
Intent so no requests are lost.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ae7aeae2-66ea-4c03-aeb6-8847a462b72e

📥 Commits

Reviewing files that changed from the base of the PR and between d45ac54 and 05ab922.

📒 Files selected for processing (5)
  • app/src/main/java/com/itsaky/androidide/actions/main/OpenTerminalAction.kt
  • app/src/main/java/com/itsaky/androidide/actions/sidebar/TerminalSidebarAction.kt
  • common/src/main/java/com/itsaky/androidide/activities/editor/HelpActivity.kt
  • common/src/main/java/com/itsaky/androidide/utils/IntentExtensions.kt
  • termux/termux-app/src/main/java/com/itsaky/androidide/activities/TerminalActivity.kt

Extract multi-window intent flags and handle new intents in TerminalActivity.
@jatezzz jatezzz force-pushed the feat/ADFA-3645-multi-window-terminal branch from 05ab922 to 8430e53 Compare April 13, 2026 13:16
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@termux/termux-app/src/main/java/com/itsaky/androidide/activities/TerminalActivity.kt`:
- Around line 67-81: Currently if mTermuxService is null the createTermuxSession
request is dropped; instead capture the pending session parameters
(newWorkingDir, isFailsafe, newSessionName or null) and enqueue them (e.g.,
store in a pendingSessionRequest field) and then replay/flush this request when
the service becomes available (in the service connection callback or where
mTermuxService is set) by calling createTermuxSession and then
mTermuxTerminalSessionActivityClient.setCurrentSession(...) as in the existing
success path; ensure only one pending request is stored or queued to avoid
duplication and clear the pendingSessionRequest after successful replay.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 451a9187-342f-4b26-8070-179d867de311

📥 Commits

Reviewing files that changed from the base of the PR and between 05ab922 and 8430e53.

📒 Files selected for processing (5)
  • app/src/main/java/com/itsaky/androidide/actions/main/OpenTerminalAction.kt
  • app/src/main/java/com/itsaky/androidide/actions/sidebar/TerminalSidebarAction.kt
  • common/src/main/java/com/itsaky/androidide/activities/editor/HelpActivity.kt
  • common/src/main/java/com/itsaky/androidide/utils/IntentExtensions.kt
  • termux/termux-app/src/main/java/com/itsaky/androidide/activities/TerminalActivity.kt
🚧 Files skipped from review as they are similar to previous changes (3)
  • app/src/main/java/com/itsaky/androidide/actions/main/OpenTerminalAction.kt
  • app/src/main/java/com/itsaky/androidide/actions/sidebar/TerminalSidebarAction.kt
  • common/src/main/java/com/itsaky/androidide/utils/IntentExtensions.kt

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@termux/termux-app/src/main/java/com/itsaky/androidide/activities/TerminalActivity.kt`:
- Around line 61-67: The replay check in TerminalActivity incorrectly skips
creating a session when both pendingWorkingDir and pendingSessionName are null
but a pending intent still expects action (e.g., pendingIsFailsafe true); add a
dedicated flag (e.g., pendingSessionPending) that onNewIntent sets whenever you
cache intent state and clear only after replay, then change the service-ready
block to call createAndSetSession(termuxService, pendingWorkingDir,
pendingSessionName, pendingIsFailsafe) whenever pendingSessionPending is true
(or pendingIsFailsafe remains true) rather than relying solely on
(pendingWorkingDir != null || pendingSessionName != null); update
onServiceConnected and onNewIntent to set/clear pendingSessionPending
appropriately and ensure pendingWorkingDir/pendingSessionName/pendingIsFailsafe
are reset after createAndSetSession.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dd196d5b-3d0c-4787-889f-9012224e3d55

📥 Commits

Reviewing files that changed from the base of the PR and between 8430e53 and bdd8c75.

📒 Files selected for processing (1)
  • termux/termux-app/src/main/java/com/itsaky/androidide/activities/TerminalActivity.kt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants