remoteInterface: support append commands to exist sessions

This commit is contained in:
imkiva 2019-01-09 16:44:50 +08:00
parent cc862be3f1
commit 3e15bbd2f7
No known key found for this signature in database
GPG Key ID: A0A40A816B1689AA
4 changed files with 89 additions and 40 deletions

View File

@ -46,6 +46,7 @@ public class TerminalSession extends TerminalOutput {
}
@SuppressWarnings("JavaReflectionMemberAccess")
private static FileDescriptor wrapFileDescriptor(int fileDescriptor) {
FileDescriptor result = new FileDescriptor();
try {
@ -70,18 +71,18 @@ public class TerminalSession extends TerminalOutput {
public final String mHandle = UUID.randomUUID().toString();
TerminalEmulator mEmulator;
private TerminalEmulator mEmulator;
/**
* A queue written to from a separate thread when the process outputs, and read by main thread to process by
* terminal emulator.
*/
final ByteQueue mProcessToTerminalIOQueue = new ByteQueue(4096);
private final ByteQueue mProcessToTerminalIOQueue = new ByteQueue(4096);
/**
* A queue written to from the main thread due to user interaction, and read by another thread which forwards by
* writing to the {@link #mTerminalFileDescriptor}.
*/
final ByteQueue mTerminalToProcessIOQueue = new ByteQueue(4096);
private final ByteQueue mTerminalToProcessIOQueue = new ByteQueue(4096);
/** Buffer to write translate code points into utf8 before writing to mTerminalToProcessIOQueue */
private final byte[] mUtf8InputBuffer = new byte[5];
@ -90,13 +91,13 @@ public class TerminalSession extends TerminalOutput {
}
/** Callback which gets notified when a session finishes or changes title. */
final SessionChangedCallback mChangeCallback;
private final SessionChangedCallback mChangeCallback;
/** The pid of the executablePath process. 0 if not started and -1 if finished running. */
int mShellPid;
private int mShellPid;
/** The exit status of the executablePath process. Only valid if ${@link #mShellPid} is -1. */
int mShellExitStatus;
private int mShellExitStatus;
/**
* The file descriptor referencing the master half of a pseudo-terminal pair, resulting from calling
@ -108,7 +109,7 @@ public class TerminalSession extends TerminalOutput {
public String mSessionName;
@SuppressLint("HandlerLeak")
final Handler mMainThreadHandler = new Handler() {
private final Handler mMainThreadHandler = new Handler() {
final byte[] mReceiveBuffer = new byte[4 * 1024];
@Override
@ -266,7 +267,7 @@ public class TerminalSession extends TerminalOutput {
}
/** Notify the {@link #mChangeCallback} that the screen has changed. */
protected void notifyScreenUpdate() {
private void notifyScreenUpdate() {
mChangeCallback.onTextChanged(this);
}
@ -282,7 +283,8 @@ public class TerminalSession extends TerminalOutput {
try {
Os.kill(mShellPid, OsConstants.SIGKILL);
} catch (ErrnoException e) {
Log.w("neoterm-termux", "Failed sending SIGKILL: " + e.getMessage());
Log.w("neoterm-shell-session",
"Failed sending SIGKILL: " + e.getMessage());
}
}
}
@ -301,7 +303,7 @@ public class TerminalSession extends TerminalOutput {
}
/** Cleanup resources when the process exits. */
void cleanupResources(int exitStatus) {
private void cleanupResources(int exitStatus) {
synchronized (this) {
mShellPid = -1;
mShellExitStatus = exitStatus;

View File

@ -6,6 +6,7 @@ import io.neoterm.backend.TerminalSession
* @author kiva
*/
class ShellParameter {
var sessionId: String? = null;
var executablePath: String? = null
var arguments: Array<String>? = null
var cwd: String? = null
@ -54,4 +55,13 @@ class ShellParameter {
this.shellProfile = shellProfile
return this
}
fun session(sessionId: String?): ShellParameter {
this.sessionId = sessionId
return this
}
fun willCreateNewSession(): Boolean {
return sessionId == null
}
}

View File

@ -77,8 +77,7 @@ class NeoTermService : Service() {
get() = mXSessions
fun createTermSession(parameter: ShellParameter): TerminalSession {
val session = TerminalUtils.createSession(this, parameter)
mTerminalSessions.add(session)
val session = createOrFindSession(parameter)
updateNotification()
return session
}
@ -108,6 +107,22 @@ class NeoTermService : Service() {
return indexOfRemoved
}
private fun createOrFindSession(parameter: ShellParameter): TerminalSession {
if (parameter.willCreateNewSession()) {
val session = TerminalUtils.createSession(this, parameter)
mTerminalSessions.add(session)
return session
}
// TODO: find session by id
val sessionId = parameter.sessionId!!
val session = mTerminalSessions.find { it.mHandle == sessionId }
?: throw IllegalArgumentException("cannot find session by given id")
session.write(parameter.initialCommand + "\n")
return session
}
private fun updateNotification() {
val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
service.notify(NOTIFICATION_ID, createNotification())
@ -165,7 +180,8 @@ class NeoTermService : Service() {
private fun acquireLock() {
if (mWakeLock == null) {
val pm = getSystemService(Context.POWER_SERVICE) as PowerManager
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, EmulatorDebug.LOG_TAG)
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
EmulatorDebug.LOG_TAG + ":")
mWakeLock!!.acquire()
val wm = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager

View File

@ -1,5 +1,6 @@
package io.neoterm.ui.term
import android.app.Activity
import android.content.ComponentName
import android.content.Intent
import android.content.ServiceConnection
@ -83,10 +84,16 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
return
}
val command = intent.getStringExtra(EXTRA_COMMAND)
openTerm(command)
val foreground = intent.getBooleanExtra(EXTRA_FOREGROUND, true)
val session = if (intent.hasExtra(EXTRA_SESSION_ID)) {
intent.getStringExtra(EXTRA_SESSION_ID)
} else {
null
}
openTerm(command, session, foreground)
}
else -> openTerm(null)
else -> openTerm(null, null)
}
finish()
}
@ -98,13 +105,15 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
val path = MediaUtils.getPath(this, extra)
val file = File(path)
val dirPath = if (file.isDirectory) path else file.parent
openTerm("cd " + TerminalUtils.escapeString(dirPath))
val command = "cd " + TerminalUtils.escapeString(dirPath)
openTerm(command, null)
}
finish()
} else {
App.get().errorDialog(this,
getString(R.string.unsupported_term_here, intent?.toString()),
{ finish() })
getString(R.string.unsupported_term_here, intent?.toString())) {
finish()
}
}
}
@ -124,10 +133,10 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
when (extra) {
is ArrayList<*> -> {
extra.takeWhile { it is Uri }
.mapTo(filesToHandle, {
.mapTo(filesToHandle) {
val uri = it as Uri
File(MediaUtils.getPath(this, uri)).absolutePath
})
}
}
is Uri -> {
filesToHandle.add(File(MediaUtils.getPath(this, extra)).absolutePath)
@ -142,8 +151,8 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
setupUserScriptView(filesToHandle, userScripts)
} else {
App.get().errorDialog(this,
getString(R.string.no_files_selected, intent?.toString()),
{ finish() })
getString(R.string.no_files_selected, intent?.toString())
) { finish() }
}
}
@ -155,10 +164,10 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
filesList.setOnItemClickListener { _, _, position, _ ->
AlertDialog.Builder(this@NeoTermRemoteInterface)
.setMessage(R.string.confirm_remove_file_from_list)
.setPositiveButton(android.R.string.yes, { _, _ ->
.setPositiveButton(android.R.string.yes) { _, _ ->
filesToHandle.removeAt(position)
filesAdapter.notifyDataSetChanged()
})
}
.setNegativeButton(android.R.string.no, null)
.show()
}
@ -186,17 +195,35 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
return arguments.toTypedArray()
}
private fun openTerm(parameter: ShellParameter) {
private fun openTerm(parameter: ShellParameter,
foreground: Boolean = true) {
val session = termService!!.createTermSession(parameter)
// Set current session to our new one
// In order to switch to it when entering NeoTermActivity
NeoPreference.storeCurrentSession(session)
if (foreground) {
// Set current session to our new one
// In order to switch to it when entering NeoTermActivity
NeoPreference.storeCurrentSession(session)
val intent = Intent(this, NeoTermActivity::class.java)
intent.addCategory(Intent.CATEGORY_DEFAULT)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
val intent = Intent(this, NeoTermActivity::class.java)
intent.addCategory(Intent.CATEGORY_DEFAULT)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
}
val data = Intent()
data.putExtra(EXTRA_SESSION_ID, session.mHandle)
setResult(Activity.RESULT_OK, data)
}
private fun openTerm(initialCommand: String?,
sessionId: String? = null,
foreground: Boolean = true) {
val parameter = ShellParameter()
.initialCommand(initialCommand)
.callback(TermSessionCallback())
.systemShell(detectSystemShell())
.session(sessionId)
openTerm(parameter, foreground)
}
private fun openCustomExecTerm(executablePath: String?, arguments: Array<String>?, cwd: String?) {
@ -209,14 +236,6 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
openTerm(parameter)
}
private fun openTerm(initialCommand: String?) {
val parameter = ShellParameter()
.initialCommand(initialCommand)
.callback(TermSessionCallback())
.systemShell(detectSystemShell())
openTerm(parameter)
}
private fun detectSystemShell(): Boolean {
return false
}
@ -224,5 +243,7 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
companion object {
const val ACTION_EXECUTE = "neoterm.action.remote.execute"
const val EXTRA_COMMAND = "neoterm.extra.remote.execute.command"
const val EXTRA_SESSION_ID = "neoterm.extra.remote.execute.session"
const val EXTRA_FOREGROUND = "neoterm.extra.remote.execute.foreground"
}
}