diff --git a/controller/app/src/main/AndroidManifest.xml b/controller/app/src/main/AndroidManifest.xml
index 7d264777..12278a57 100644
--- a/controller/app/src/main/AndroidManifest.xml
+++ b/controller/app/src/main/AndroidManifest.xml
@@ -70,6 +70,17 @@
adjustPan, so the IME covered the ExtraKeys bar and the text stuck. adjustResize shrinks the
window so the extra-keys bar + terminal sit above the keyboard. -->
+
+
+
{
+ terminalController.openFullTerminal();
+ // Attach finish-on-hide only after the sheet has been expanded, so the initial
+ // HIDDEN state (set in bind()) can never reach a live callback and close the
+ // Activity on launch. Mirrors MainActivity, which attached it inside the open.
+ attachFinishOnHide();
+ };
+ if (root != null) root.post(open);
+ else open.run();
+ }
+
+ /**
+ * Swiping the terminal sheet down finishes back to the caller instead of exposing an
+ * empty surface. Mirrors MainActivity.attachTerminalOnlyFinish (ADFA-4987): no peek
+ * stop — a swipe-down goes straight to HIDDEN -> finish(). Attached once (after the
+ * first expand); a re-open via onNewIntent must not stack a second callback.
+ */
+ private void attachFinishOnHide() {
+ if (finishOnHideAttached) return;
+ View sheet = findViewById(R.id.terminal_bottom_sheet);
+ if (sheet == null) return;
+ BottomSheetBehavior b = BottomSheetBehavior.from(sheet);
+ b.setHideable(true);
+ b.setSkipCollapsed(true);
+ b.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
+ @Override
+ public void onStateChanged(@NonNull View bottomSheet, int newState) {
+ if (newState == BottomSheetBehavior.STATE_HIDDEN) {
+ finish();
+ }
+ }
+
+ @Override
+ public void onSlide(@NonNull View bottomSheet, float slideOffset) { }
+ });
+ finishOnHideAttached = true;
+ }
+
+ @Override
+ protected void onDestroy() {
+ // Release the terminal UI delegate so the app-scoped session store never holds a
+ // destroyed Activity; running sessions keep going (ADFA-4696).
+ if (terminalController != null) terminalController.detach();
+ super.onDestroy();
+ }
+
+ // --- TerminalController.Host ---------------------------------------------
+ @Override
+ public void addToLog(String message) {
+ // Single source of truth; the Usage console observes LogRepository (ADFA-4640).
+ LogRepository.get().append(message);
+ }
+
+ @Override
+ public void vibrateDevice() {
+ android.os.Vibrator v = (android.os.Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
+ if (v != null && v.hasVibrator()) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ v.vibrate(android.os.VibrationEffect.createOneShot(50, android.os.VibrationEffect.DEFAULT_AMPLITUDE));
+ } else {
+ v.vibrate(50);
+ }
+ }
+ }
+}
diff --git a/controller/app/src/main/java/org/iiab/controller/TerminalSessionService.java b/controller/app/src/main/java/org/iiab/controller/TerminalSessionService.java
index e7a795e3..fbc9bbb8 100644
--- a/controller/app/src/main/java/org/iiab/controller/TerminalSessionService.java
+++ b/controller/app/src/main/java/org/iiab/controller/TerminalSessionService.java
@@ -93,11 +93,10 @@ CHANNEL_ID, getString(R.string.terminal_channel_name),
}
private Notification buildNotification() {
- // Tapping the notification opens the terminal directly, bypassing the hidden
- // version-footer gesture (ADFA-4696). SINGLE_TOP reuses the running Activity.
- Intent open = new Intent(this, MainActivity.class)
- .putExtra(MainActivity.EXTRA_OPEN_TERMINAL, true)
- .putExtra(MainActivity.EXTRA_TERMINAL_ONLY, true)
+ // Tapping the notification opens the terminal directly (ADFA-4696). ADFA-5192: the terminal
+ // is its own Activity now, so no terminal-only extras are needed. SINGLE_TOP reuses the
+ // running instance.
+ Intent open = new Intent(this, TerminalActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pending = PendingIntent.getActivity(
this, 0, open, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
diff --git a/controller/app/src/main/java/org/iiab/controller/redesign/SettingsSubFragment.java b/controller/app/src/main/java/org/iiab/controller/redesign/SettingsSubFragment.java
index 6761ee64..3570948d 100644
--- a/controller/app/src/main/java/org/iiab/controller/redesign/SettingsSubFragment.java
+++ b/controller/app/src/main/java/org/iiab/controller/redesign/SettingsSubFragment.java
@@ -205,12 +205,9 @@ private void openAppSettings(Context ctx) {
} catch (Exception ignore) { /* no-op */ }
}
- /** The full Debian terminal lives in MainActivity; EXTRA_OPEN_TERMINAL opens it directly. */
+ /** The full Debian terminal lives in its own TerminalActivity (ADFA-5192). */
private void openTerminal(Context ctx) {
- Intent i = new Intent(ctx, org.iiab.controller.MainActivity.class);
- i.putExtra(org.iiab.controller.MainActivity.EXTRA_OPEN_TERMINAL, true);
- i.putExtra(org.iiab.controller.MainActivity.EXTRA_TERMINAL_ONLY, true);
- ctx.startActivity(i);
+ ctx.startActivity(new Intent(ctx, org.iiab.controller.TerminalActivity.class));
}
// ---- Advanced (power-user features — preview for now) ----
diff --git a/controller/app/src/main/res/layout/terminal_activity.xml b/controller/app/src/main/res/layout/terminal_activity.xml
new file mode 100644
index 00000000..5dd5b9c7
--- /dev/null
+++ b/controller/app/src/main/res/layout/terminal_activity.xml
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+