Skip to content

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

Open
jatezzz wants to merge 1 commit intostagefrom
feat/ADFA-3645-multi-window-terminal
Open

ADFA-3645 | Open terminal in adjacent window on large screens#1173
jatezzz wants to merge 1 commit 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.

Extract multi-window intent flags and handle new intents in TerminalActivity.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 10, 2026

📝 Walkthrough

Release Notes - Terminal Multi-Window Support (ADFA-3645)

Features

  • Multi-window terminal support: Terminal now launches in an adjacent window (split-screen) on large-screen devices (tablets, DeX) enabling simultaneous view of editor and terminal
  • Centralized intent flag management: New Intent.applyMultiWindowFlags() extension function consolidates multi-window configuration, improving maintainability
  • Intent reuse handling: TerminalActivity.onNewIntent() now properly creates new terminal sessions when the activity is re-launched with FLAG_ACTIVITY_SINGLE_TOP, ensuring new sessions use provided working directory and session name

Changes

  • Added IntentExtensions.kt with applyMultiWindowFlags() extension function that:
    • Applies FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_SINGLE_TOP | FLAG_ACTIVITY_LAUNCH_ADJACENT on large-screen devices
    • Applies only FLAG_ACTIVITY_NEW_TASK on smaller screens when context is not an Activity
  • Updated OpenTerminalAction and TerminalSidebarAction to use applyMultiWindowFlags() before launching terminal
  • Refactored HelpActivity to leverage the new extension function, reducing code duplication
  • Enhanced TerminalActivity with onNewIntent() override to instantiate new terminal sessions with provided parameters

⚠️ Risks & Best Practice Considerations

  • Complex intent flag combination: The flag combination (SINGLE_TOP + NEW_TASK + LAUNCH_ADJACENT) is non-trivial and requires testing on DeX and tablet devices to ensure expected split-screen behavior and prevent unintended activity stack reordering
  • Silent failure handling: onNewIntent() silently returns if mTermuxService is null or createTermuxSession() fails. No user feedback or logging on failure cases. Consider adding logging or user notification
  • Service initialization timing: Implementation assumes mTermuxService is initialized by the time onNewIntent() is called; unexpected null states could silently prevent session creation
  • Recommendation: Thoroughly test on Samsung DeX and various Android tablets; add debug logging to track session creation success/failure in onNewIntent()

Walkthrough

This PR introduces a new applyMultiWindowFlags() extension function to centralize multi-window intent flag handling based on device form factor, refactors three activities to use this utility, and adds onNewIntent() handling to TerminalActivity for creating new terminal sessions from incoming intents.

Changes

Cohort / File(s) Summary
Intent Utilities
common/src/main/java/com/itsaky/androidide/utils/IntentExtensions.kt
New extension function applyMultiWindowFlags(context: Context) that conditionally applies multi-window flags (NEW_TASK, NEW_DOCUMENT, SINGLE_TOP, LAUNCH_ADJACENT) for large-screen devices, and FLAG_ACTIVITY_NEW_TASK for non-Activity contexts on smaller screens.
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 to apply multi-window flags via applyMultiWindowFlags() before starting activities, centralizing flag handling and removing inline flag logic.
Terminal Intent Handling
termux/termux-app/src/main/java/com/itsaky/androidide/activities/TerminalActivity.kt
Added onNewIntent() override to extract session-related extras (working directory, session name, failsafe flag) and create new Termux sessions dynamically when new intents arrive.

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 new Intent()
    Activity->>Ext: intent.applyMultiWindowFlags(context)
    Ext->>DFF: getCurrent(context)
    alt Large Screen Device
        Ext->>Intent: add NEW_TASK, NEW_DOCUMENT, SINGLE_TOP, LAUNCH_ADJACENT flags
    else Non-Large Screen
        Ext->>Intent: add FLAG_ACTIVITY_NEW_TASK (if non-Activity context)
    end
    Ext-->>Intent: return modified Intent
    Activity->>AM: startActivity(intent)

    rect rgba(100, 150, 200, 0.5)
        Note over Activity,AM: Multi-window intent launching flow
    end
Loading
sequenceDiagram
    participant System as System/Intent Router
    participant TA as TerminalActivity
    participant TS as TermuxService
    participant Session as TermuxSession

    System->>TA: onNewIntent(intent)
    TA->>TA: setIntent(intent)
    TA->>TA: extract extras (workDir, sessionName, failsafe)
    alt mTermuxService Available
        TA->>TS: createTermuxSession(workDir, sessionName, failsafe)
        TS-->>Session: newSession
        alt Session Created Successfully
            TA->>TA: setCurrentSession(newSession.terminalSession)
        end
    end

    rect rgba(150, 100, 200, 0.5)
        Note over System,Session: Terminal session creation from intent
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • itsaky-adfa
  • Daniel-ADFA
  • dara-abijo-adfa

Poem

🐰 Hops through intents with multi-window glee,
Flags are unified for all to see!
New sessions bloom when terminals arise,
Form factors bend to screen device size. ✨📱

🚥 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 clearly and specifically describes the main change: enabling terminal launch in adjacent windows on large screens, which aligns with the core functionality added across multiple files.
Description check ✅ Passed The description is directly related to the changeset, providing clear context about the multi-window terminal feature, the extracted extension function, and the onNewIntent handling, all of which are present in the changes.

✏️ 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

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.

1 participant