remoteInterface: support append commands to exist sessions
This commit is contained in:
@ -46,6 +46,7 @@ public class TerminalSession extends TerminalOutput {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("JavaReflectionMemberAccess")
|
||||||
private static FileDescriptor wrapFileDescriptor(int fileDescriptor) {
|
private static FileDescriptor wrapFileDescriptor(int fileDescriptor) {
|
||||||
FileDescriptor result = new FileDescriptor();
|
FileDescriptor result = new FileDescriptor();
|
||||||
try {
|
try {
|
||||||
@ -70,18 +71,18 @@ public class TerminalSession extends TerminalOutput {
|
|||||||
|
|
||||||
public final String mHandle = UUID.randomUUID().toString();
|
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
|
* A queue written to from a separate thread when the process outputs, and read by main thread to process by
|
||||||
* terminal emulator.
|
* 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
|
* 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}.
|
* 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 */
|
/** Buffer to write translate code points into utf8 before writing to mTerminalToProcessIOQueue */
|
||||||
private final byte[] mUtf8InputBuffer = new byte[5];
|
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. */
|
/** 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. */
|
/** 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. */
|
/** 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
|
* 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;
|
public String mSessionName;
|
||||||
|
|
||||||
@SuppressLint("HandlerLeak")
|
@SuppressLint("HandlerLeak")
|
||||||
final Handler mMainThreadHandler = new Handler() {
|
private final Handler mMainThreadHandler = new Handler() {
|
||||||
final byte[] mReceiveBuffer = new byte[4 * 1024];
|
final byte[] mReceiveBuffer = new byte[4 * 1024];
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -266,7 +267,7 @@ public class TerminalSession extends TerminalOutput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Notify the {@link #mChangeCallback} that the screen has changed. */
|
/** Notify the {@link #mChangeCallback} that the screen has changed. */
|
||||||
protected void notifyScreenUpdate() {
|
private void notifyScreenUpdate() {
|
||||||
mChangeCallback.onTextChanged(this);
|
mChangeCallback.onTextChanged(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,7 +283,8 @@ public class TerminalSession extends TerminalOutput {
|
|||||||
try {
|
try {
|
||||||
Os.kill(mShellPid, OsConstants.SIGKILL);
|
Os.kill(mShellPid, OsConstants.SIGKILL);
|
||||||
} catch (ErrnoException e) {
|
} 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. */
|
/** Cleanup resources when the process exits. */
|
||||||
void cleanupResources(int exitStatus) {
|
private void cleanupResources(int exitStatus) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
mShellPid = -1;
|
mShellPid = -1;
|
||||||
mShellExitStatus = exitStatus;
|
mShellExitStatus = exitStatus;
|
||||||
|
@ -6,6 +6,7 @@ import io.neoterm.backend.TerminalSession
|
|||||||
* @author kiva
|
* @author kiva
|
||||||
*/
|
*/
|
||||||
class ShellParameter {
|
class ShellParameter {
|
||||||
|
var sessionId: String? = null;
|
||||||
var executablePath: String? = null
|
var executablePath: String? = null
|
||||||
var arguments: Array<String>? = null
|
var arguments: Array<String>? = null
|
||||||
var cwd: String? = null
|
var cwd: String? = null
|
||||||
@ -54,4 +55,13 @@ class ShellParameter {
|
|||||||
this.shellProfile = shellProfile
|
this.shellProfile = shellProfile
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun session(sessionId: String?): ShellParameter {
|
||||||
|
this.sessionId = sessionId
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun willCreateNewSession(): Boolean {
|
||||||
|
return sessionId == null
|
||||||
|
}
|
||||||
}
|
}
|
@ -77,8 +77,7 @@ class NeoTermService : Service() {
|
|||||||
get() = mXSessions
|
get() = mXSessions
|
||||||
|
|
||||||
fun createTermSession(parameter: ShellParameter): TerminalSession {
|
fun createTermSession(parameter: ShellParameter): TerminalSession {
|
||||||
val session = TerminalUtils.createSession(this, parameter)
|
val session = createOrFindSession(parameter)
|
||||||
mTerminalSessions.add(session)
|
|
||||||
updateNotification()
|
updateNotification()
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
@ -108,6 +107,22 @@ class NeoTermService : Service() {
|
|||||||
return indexOfRemoved
|
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() {
|
private fun updateNotification() {
|
||||||
val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
service.notify(NOTIFICATION_ID, createNotification())
|
service.notify(NOTIFICATION_ID, createNotification())
|
||||||
@ -165,7 +180,8 @@ class NeoTermService : Service() {
|
|||||||
private fun acquireLock() {
|
private fun acquireLock() {
|
||||||
if (mWakeLock == null) {
|
if (mWakeLock == null) {
|
||||||
val pm = getSystemService(Context.POWER_SERVICE) as PowerManager
|
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()
|
mWakeLock!!.acquire()
|
||||||
|
|
||||||
val wm = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
val wm = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package io.neoterm.ui.term
|
package io.neoterm.ui.term
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.ServiceConnection
|
import android.content.ServiceConnection
|
||||||
@ -83,10 +84,16 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
val command = intent.getStringExtra(EXTRA_COMMAND)
|
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()
|
finish()
|
||||||
}
|
}
|
||||||
@ -98,13 +105,15 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
|
|||||||
val path = MediaUtils.getPath(this, extra)
|
val path = MediaUtils.getPath(this, extra)
|
||||||
val file = File(path)
|
val file = File(path)
|
||||||
val dirPath = if (file.isDirectory) path else file.parent
|
val dirPath = if (file.isDirectory) path else file.parent
|
||||||
openTerm("cd " + TerminalUtils.escapeString(dirPath))
|
val command = "cd " + TerminalUtils.escapeString(dirPath)
|
||||||
|
openTerm(command, null)
|
||||||
}
|
}
|
||||||
finish()
|
finish()
|
||||||
} else {
|
} else {
|
||||||
App.get().errorDialog(this,
|
App.get().errorDialog(this,
|
||||||
getString(R.string.unsupported_term_here, intent?.toString()),
|
getString(R.string.unsupported_term_here, intent?.toString())) {
|
||||||
{ finish() })
|
finish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,10 +133,10 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
|
|||||||
when (extra) {
|
when (extra) {
|
||||||
is ArrayList<*> -> {
|
is ArrayList<*> -> {
|
||||||
extra.takeWhile { it is Uri }
|
extra.takeWhile { it is Uri }
|
||||||
.mapTo(filesToHandle, {
|
.mapTo(filesToHandle) {
|
||||||
val uri = it as Uri
|
val uri = it as Uri
|
||||||
File(MediaUtils.getPath(this, uri)).absolutePath
|
File(MediaUtils.getPath(this, uri)).absolutePath
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
is Uri -> {
|
is Uri -> {
|
||||||
filesToHandle.add(File(MediaUtils.getPath(this, extra)).absolutePath)
|
filesToHandle.add(File(MediaUtils.getPath(this, extra)).absolutePath)
|
||||||
@ -142,8 +151,8 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
|
|||||||
setupUserScriptView(filesToHandle, userScripts)
|
setupUserScriptView(filesToHandle, userScripts)
|
||||||
} else {
|
} else {
|
||||||
App.get().errorDialog(this,
|
App.get().errorDialog(this,
|
||||||
getString(R.string.no_files_selected, intent?.toString()),
|
getString(R.string.no_files_selected, intent?.toString())
|
||||||
{ finish() })
|
) { finish() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,10 +164,10 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
|
|||||||
filesList.setOnItemClickListener { _, _, position, _ ->
|
filesList.setOnItemClickListener { _, _, position, _ ->
|
||||||
AlertDialog.Builder(this@NeoTermRemoteInterface)
|
AlertDialog.Builder(this@NeoTermRemoteInterface)
|
||||||
.setMessage(R.string.confirm_remove_file_from_list)
|
.setMessage(R.string.confirm_remove_file_from_list)
|
||||||
.setPositiveButton(android.R.string.yes, { _, _ ->
|
.setPositiveButton(android.R.string.yes) { _, _ ->
|
||||||
filesToHandle.removeAt(position)
|
filesToHandle.removeAt(position)
|
||||||
filesAdapter.notifyDataSetChanged()
|
filesAdapter.notifyDataSetChanged()
|
||||||
})
|
}
|
||||||
.setNegativeButton(android.R.string.no, null)
|
.setNegativeButton(android.R.string.no, null)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
@ -186,17 +195,35 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
|
|||||||
return arguments.toTypedArray()
|
return arguments.toTypedArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun openTerm(parameter: ShellParameter) {
|
private fun openTerm(parameter: ShellParameter,
|
||||||
|
foreground: Boolean = true) {
|
||||||
val session = termService!!.createTermSession(parameter)
|
val session = termService!!.createTermSession(parameter)
|
||||||
|
|
||||||
// Set current session to our new one
|
if (foreground) {
|
||||||
// In order to switch to it when entering NeoTermActivity
|
// Set current session to our new one
|
||||||
NeoPreference.storeCurrentSession(session)
|
// In order to switch to it when entering NeoTermActivity
|
||||||
|
NeoPreference.storeCurrentSession(session)
|
||||||
|
|
||||||
val intent = Intent(this, NeoTermActivity::class.java)
|
val intent = Intent(this, NeoTermActivity::class.java)
|
||||||
intent.addCategory(Intent.CATEGORY_DEFAULT)
|
intent.addCategory(Intent.CATEGORY_DEFAULT)
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
startActivity(intent)
|
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?) {
|
private fun openCustomExecTerm(executablePath: String?, arguments: Array<String>?, cwd: String?) {
|
||||||
@ -209,14 +236,6 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
|
|||||||
openTerm(parameter)
|
openTerm(parameter)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun openTerm(initialCommand: String?) {
|
|
||||||
val parameter = ShellParameter()
|
|
||||||
.initialCommand(initialCommand)
|
|
||||||
.callback(TermSessionCallback())
|
|
||||||
.systemShell(detectSystemShell())
|
|
||||||
openTerm(parameter)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun detectSystemShell(): Boolean {
|
private fun detectSystemShell(): Boolean {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -224,5 +243,7 @@ class NeoTermRemoteInterface : AppCompatActivity(), ServiceConnection {
|
|||||||
companion object {
|
companion object {
|
||||||
const val ACTION_EXECUTE = "neoterm.action.remote.execute"
|
const val ACTION_EXECUTE = "neoterm.action.remote.execute"
|
||||||
const val EXTRA_COMMAND = "neoterm.extra.remote.execute.command"
|
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"
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user