mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-11 02:51:10 +00:00
fix(dual-screen): the bottom-screen terminal keeps its shell when another app covers that screen
This commit is contained in:
1 parent
75a0230304
commit
3b35bd7b66
4 files changed
+99
-6
No files matched your search
@@ -14,6 +14,12 @@ object SessionTerminal {
|
||||
|
||||
@Volatile private var launch: Launch? = null
|
||||
|
||||
private class Kept(val session: TerminalSession, val generation: Int)
|
||||
|
||||
// The bottom screen's presentation is dismissed whenever another app covers that display
|
||||
// (a browser opened for a sign-in), so its shell is kept for the next panel.
|
||||
@Volatile private var kept: Kept? = null
|
||||
|
||||
fun prepare(
|
||||
command: List<String>,
|
||||
hostEnvironment: Array<String>,
|
||||
@@ -32,8 +38,31 @@ object SessionTerminal {
|
||||
).also { it.mSessionName = "DroidDeck Linux shell" }
|
||||
}
|
||||
|
||||
fun reuse(client: TerminalSessionClient): TerminalSession? {
|
||||
val current = kept ?: return null
|
||||
if (current.generation != launch?.generation || !current.session.isRunning) {
|
||||
kept = null
|
||||
return null
|
||||
}
|
||||
current.session.updateTerminalSessionClient(client)
|
||||
return current.session
|
||||
}
|
||||
|
||||
fun keep(session: TerminalSession) {
|
||||
val generation = launch?.generation ?: return
|
||||
kept = Kept(session, generation)
|
||||
}
|
||||
|
||||
fun release(session: TerminalSession?) {
|
||||
if (session != null && kept?.session === session) kept = null
|
||||
}
|
||||
|
||||
fun clear(generation: Int? = null) {
|
||||
val current = launch ?: return
|
||||
if (generation == null || current.generation == generation) launch = null
|
||||
if (generation == null || current.generation == generation) {
|
||||
launch = null
|
||||
kept?.session?.takeIf { it.pid > 0 }?.finishIfRunning()
|
||||
kept = null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -364,7 +364,7 @@ class SecondScreenPresentation(
|
||||
|
||||
private fun renderTerminal() {
|
||||
bar(SecondScreenMode.TERMINAL)
|
||||
val panel = SessionTerminalPanel(context)
|
||||
val panel = SessionTerminalPanel(context, keepShell = true)
|
||||
terminalPanel = panel
|
||||
root.addView(panel, weightParams())
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import com.termux.terminal.TerminalSessionClient
|
||||
import com.termux.view.TerminalView
|
||||
import com.termux.view.TerminalViewClient
|
||||
|
||||
class SessionTerminalPanel(context: Context) : LinearLayout(context) {
|
||||
class SessionTerminalPanel(context: Context, private val keepShell: Boolean = false) : LinearLayout(context) {
|
||||
private var terminalSession: TerminalSession? = null
|
||||
private var terminalView: TerminalView? = null
|
||||
private var terminalPid = -1
|
||||
@@ -45,7 +45,8 @@ class SessionTerminalPanel(context: Context) : LinearLayout(context) {
|
||||
isFocusableInTouchMode = true
|
||||
}
|
||||
terminalView = view
|
||||
val session = SessionTerminal.create(terminalClient)
|
||||
val session = (if (keepShell) SessionTerminal.reuse(terminalClient) else null)
|
||||
?: SessionTerminal.create(terminalClient)?.also { if (keepShell) SessionTerminal.keep(it) }
|
||||
if (session == null) {
|
||||
addView(TextView(context).apply {
|
||||
text = context.getString(R.string.second_terminal_not_ready)
|
||||
@@ -121,8 +122,12 @@ class SessionTerminalPanel(context: Context) : LinearLayout(context) {
|
||||
(context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager)
|
||||
.hideSoftInputFromWindow(view.windowToken, 0)
|
||||
}
|
||||
val pid = terminalPid.takeIf { it > 1 } ?: (terminalSession?.pid ?: -1)
|
||||
if (pid > 1) SessionService.stopTerminalProcess(context, pid)
|
||||
val session = terminalSession
|
||||
if (!keepShell || session?.isRunning != true) {
|
||||
val pid = terminalPid.takeIf { it > 1 } ?: (session?.pid ?: -1)
|
||||
if (pid > 1) SessionService.stopTerminalProcess(context, pid)
|
||||
SessionTerminal.release(session)
|
||||
}
|
||||
terminalPid = -1
|
||||
terminalSession = null
|
||||
terminalView = null
|
||||
@@ -140,6 +145,7 @@ class SessionTerminalPanel(context: Context) : LinearLayout(context) {
|
||||
override fun onSessionFinished(finishedSession: TerminalSession) {
|
||||
val pid = terminalPid.takeIf { it > 1 } ?: finishedSession.pid
|
||||
if (pid > 1) SessionService.terminalProcessExited(context, pid)
|
||||
SessionTerminal.release(finishedSession)
|
||||
terminalPid = -1
|
||||
terminalView?.onScreenUpdated()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.droiddeck.launcher.session
|
||||
|
||||
import com.termux.terminal.TerminalSession
|
||||
import com.termux.terminal.TerminalSessionClient
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertSame
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import java.io.File
|
||||
import java.lang.reflect.Proxy
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [28], manifest = Config.NONE)
|
||||
class SessionTerminalKeepTest {
|
||||
private val client = Proxy.newProxyInstance(
|
||||
TerminalSessionClient::class.java.classLoader, arrayOf(TerminalSessionClient::class.java),
|
||||
) { _, method, _ -> if (method.returnType == Int::class.javaPrimitiveType) 0 else null } as TerminalSessionClient
|
||||
|
||||
private fun prepare(generation: Int) =
|
||||
SessionTerminal.prepare(listOf("/bin/sh"), emptyArray(), File("/"), generation)
|
||||
|
||||
private fun unstarted() = TerminalSession("/bin/sh", "/", arrayOf("/bin/sh"), emptyArray(), 3000, client)
|
||||
|
||||
@After fun reset() = SessionTerminal.clear()
|
||||
|
||||
@Test fun aKeptShellIsReusedByTheNextPanel() {
|
||||
prepare(1)
|
||||
val shell = unstarted()
|
||||
SessionTerminal.keep(shell)
|
||||
assertSame(shell, SessionTerminal.reuse(client))
|
||||
}
|
||||
|
||||
@Test fun aReleasedShellIsNotReused() {
|
||||
prepare(1)
|
||||
val shell = unstarted()
|
||||
SessionTerminal.keep(shell)
|
||||
SessionTerminal.release(shell)
|
||||
assertNull(SessionTerminal.reuse(client))
|
||||
}
|
||||
|
||||
@Test fun aShellFromAnEarlierSessionIsNotReused() {
|
||||
prepare(1)
|
||||
SessionTerminal.keep(unstarted())
|
||||
prepare(2)
|
||||
assertNull(SessionTerminal.reuse(client))
|
||||
}
|
||||
|
||||
@Test fun clearingTheSessionDropsTheKeptShell() {
|
||||
prepare(1)
|
||||
SessionTerminal.keep(unstarted())
|
||||
SessionTerminal.clear(1)
|
||||
prepare(1)
|
||||
assertNull(SessionTerminal.reuse(client))
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user