Project: Refactor Terminal Client
This commit is contained in:
parent
e21d7ccf6f
commit
bdc8f60da0
@ -17,8 +17,8 @@ android {
|
||||
applicationId "io.neoterm"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 25
|
||||
versionCode 13
|
||||
versionName "1.2.0-rc2"
|
||||
versionCode 14
|
||||
versionName "1.2.0-rc3"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
resConfigs "zh"
|
||||
externalNativeBuild {
|
||||
|
@ -28,7 +28,7 @@ import java.util.UUID;
|
||||
* <p>
|
||||
* NOTE: The terminal session may outlive the EmulatorView, so be careful with callbacks!
|
||||
*/
|
||||
public final class TerminalSession extends TerminalOutput {
|
||||
public class TerminalSession extends TerminalOutput {
|
||||
|
||||
/** Callback to be invoked when a {@link TerminalSession} changes. */
|
||||
public interface SessionChangedCallback {
|
||||
@ -143,18 +143,16 @@ public final class TerminalSession extends TerminalOutput {
|
||||
|
||||
private final String mShellPath;
|
||||
private final String mCwd;
|
||||
private final String mInitialCommand;
|
||||
private final String[] mArgs;
|
||||
private final String[] mEnv;
|
||||
|
||||
public TerminalSession(String shellPath, String cwd, String initialCommand, String[] args, String[] env, SessionChangedCallback changeCallback) {
|
||||
public TerminalSession(String shellPath, String cwd, String[] args, String[] env, SessionChangedCallback changeCallback) {
|
||||
mChangeCallback = changeCallback;
|
||||
|
||||
this.mShellPath = shellPath;
|
||||
this.mCwd = cwd;
|
||||
this.mArgs = args;
|
||||
this.mEnv = env;
|
||||
this.mInitialCommand = initialCommand;
|
||||
}
|
||||
|
||||
/** Inform the attached pty of the new size and reflow or initialize the emulator. */
|
||||
@ -227,10 +225,6 @@ public final class TerminalSession extends TerminalOutput {
|
||||
mMainThreadHandler.sendMessage(mMainThreadHandler.obtainMessage(MSG_PROCESS_EXITED, processExitCode));
|
||||
}
|
||||
}.start();
|
||||
|
||||
if (mInitialCommand != null && mInitialCommand.length() > 0) {
|
||||
write(mInitialCommand + '\r');
|
||||
}
|
||||
}
|
||||
|
||||
/** Write data to the shell process. */
|
||||
|
@ -96,67 +96,6 @@ object NeoPreference {
|
||||
return null
|
||||
}
|
||||
|
||||
fun buildEnvironment(cwd: String?, systemShell: Boolean, executablePath: String): Array<String> {
|
||||
var cwd = cwd
|
||||
File(NeoTermPath.HOME_PATH).mkdirs()
|
||||
|
||||
if (cwd == null) cwd = NeoTermPath.HOME_PATH
|
||||
|
||||
val termEnv = "TERM=xterm-256color"
|
||||
val homeEnv = "HOME=" + NeoTermPath.HOME_PATH
|
||||
val androidRootEnv = "ANDROID_ROOT=" + System.getenv("ANDROID_ROOT")
|
||||
val androidDataEnv = "ANDROID_DATA=" + System.getenv("ANDROID_DATA")
|
||||
val externalStorageEnv = "EXTERNAL_STORAGE=" + System.getenv("EXTERNAL_STORAGE")
|
||||
|
||||
if (systemShell) {
|
||||
val pathEnv = "PATH=" + System.getenv("PATH")
|
||||
return arrayOf(termEnv, homeEnv, androidRootEnv, androidDataEnv, externalStorageEnv, pathEnv)
|
||||
|
||||
} else {
|
||||
val ps1Env = "PS1=$ "
|
||||
val langEnv = "LANG=en_US.UTF-8"
|
||||
val pathEnv = "PATH=" + buildPathEnv()
|
||||
val ldEnv = "LD_LIBRARY_PATH=" + buildLdLibraryEnv()
|
||||
val pwdEnv = "PWD=" + cwd
|
||||
val tmpdirEnv = "TMPDIR=${NeoTermPath.USR_PATH}/tmp"
|
||||
|
||||
return arrayOf(termEnv, homeEnv, ps1Env, ldEnv, langEnv, pathEnv, pwdEnv, androidRootEnv, androidDataEnv, externalStorageEnv, tmpdirEnv)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildLdLibraryEnv(): String {
|
||||
val builder = StringBuilder("${NeoTermPath.USR_PATH}/lib")
|
||||
|
||||
val programSelection = NeoPreference.loadString(R.string.key_general_program_selection, VALUE_NEOTERM_ONLY)
|
||||
val systemPath = System.getenv("LD_LIBRARY_PATH")
|
||||
|
||||
if (programSelection != VALUE_NEOTERM_ONLY) {
|
||||
builder.append(":$systemPath")
|
||||
}
|
||||
|
||||
return builder.toString()
|
||||
}
|
||||
|
||||
private fun buildPathEnv(): String {
|
||||
val builder = StringBuilder()
|
||||
val programSelection = NeoPreference.loadString(R.string.key_general_program_selection, VALUE_NEOTERM_ONLY)
|
||||
val basePath = "${NeoTermPath.USR_PATH}/bin:${NeoTermPath.USR_PATH}/bin/applets"
|
||||
val systemPath = System.getenv("PATH")
|
||||
|
||||
when (programSelection) {
|
||||
VALUE_NEOTERM_ONLY -> {
|
||||
builder.append(basePath)
|
||||
}
|
||||
VALUE_NEOTERM_FIRST -> {
|
||||
builder.append("$basePath:$systemPath")
|
||||
}
|
||||
VALUE_SYSTEM_FIRST -> {
|
||||
builder.append("$systemPath:$basePath")
|
||||
}
|
||||
}
|
||||
return builder.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* To print the job name about to be executed in bash:
|
||||
|
@ -76,8 +76,11 @@ class NeoTermService : Service() {
|
||||
val sessions: List<TerminalSession>
|
||||
get() = mTerminalSessions
|
||||
|
||||
fun createTermSession(executablePath: String?, arguments: Array<String>?, cwd: String?, initialCommand: String?, env: Array<String>?, sessionCallback: TerminalSession.SessionChangedCallback?, systemShell: Boolean): TerminalSession {
|
||||
val session = TerminalUtils.createSession(this, executablePath, arguments, cwd, initialCommand, env, sessionCallback, systemShell)
|
||||
fun createTermSession(executablePath: String?, arguments: Array<String>?,
|
||||
cwd: String?, initialCommand: String?,
|
||||
env: Array<Pair<String, String>>?, sessionCallback:
|
||||
TerminalSession.SessionChangedCallback?, systemShell: Boolean): TerminalSession {
|
||||
val session = TerminalUtils.createShellSession(this, executablePath, arguments, cwd, initialCommand, env, sessionCallback, systemShell)
|
||||
mTerminalSessions.add(session)
|
||||
updateNotification()
|
||||
return session
|
||||
|
199
app/src/main/java/io/neoterm/terminal/ShellTermSession.kt
Normal file
199
app/src/main/java/io/neoterm/terminal/ShellTermSession.kt
Normal file
@ -0,0 +1,199 @@
|
||||
package io.neoterm.terminal
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.Toast
|
||||
import io.neoterm.R
|
||||
import io.neoterm.backend.TerminalSession
|
||||
import io.neoterm.preference.NeoPreference
|
||||
import io.neoterm.preference.NeoTermPath
|
||||
import io.neoterm.terminal.client.TermSessionCallback
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
open class ShellTermSession private constructor(shellPath: String, cwd: String, args: Array<String>, env: Array<String>, changeCallback: SessionChangedCallback) : TerminalSession(shellPath, cwd, args, env, changeCallback) {
|
||||
var initialCommand : String? = null
|
||||
|
||||
override fun initializeEmulator(columns: Int, rows: Int) {
|
||||
super.initializeEmulator(columns, rows)
|
||||
|
||||
val initCommand = initialCommand
|
||||
if (initCommand != null && initCommand.isNotEmpty()) {
|
||||
write(initCommand + '\r')
|
||||
}
|
||||
}
|
||||
|
||||
class Builder {
|
||||
private var shell: String? = null
|
||||
private var cwd: String? = null
|
||||
private var args: MutableList<String>? = null
|
||||
private var env: MutableList<Pair<String, String>>? = null
|
||||
private var changeCallback: SessionChangedCallback? = null
|
||||
private var systemShell = false
|
||||
|
||||
fun shell(shell: String?): Builder {
|
||||
this.shell = shell
|
||||
return this
|
||||
}
|
||||
|
||||
fun currentWorkingDirectory(cwd: String?): Builder {
|
||||
this.cwd = cwd
|
||||
return this
|
||||
}
|
||||
|
||||
fun arg(arg: String?): Builder {
|
||||
if (arg != null) {
|
||||
if (args == null) {
|
||||
args = mutableListOf(arg)
|
||||
} else {
|
||||
args!!.add(arg)
|
||||
}
|
||||
} else {
|
||||
this.args = null
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun argArray(args: Array<String>?): Builder {
|
||||
if (args != null) {
|
||||
if (args.isEmpty()) {
|
||||
this.args = null
|
||||
return this
|
||||
}
|
||||
args.forEach { arg(it) }
|
||||
} else {
|
||||
this.args = null
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun env(env: Pair<String, String>?): Builder {
|
||||
if (env != null) {
|
||||
if (this.env == null) {
|
||||
this.env = mutableListOf(env)
|
||||
} else {
|
||||
this.env!!.add(env)
|
||||
}
|
||||
} else {
|
||||
this.env = null
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun envArray(env: Array<Pair<String, String>>?): Builder {
|
||||
if (env != null) {
|
||||
if (env.isEmpty()) {
|
||||
this.env = null
|
||||
return this
|
||||
}
|
||||
env.forEach { env(it) }
|
||||
} else {
|
||||
this.env = null
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun callback(callback: SessionChangedCallback?): Builder {
|
||||
this.changeCallback = callback
|
||||
return this
|
||||
}
|
||||
|
||||
fun systemShell(systemShell: Boolean): Builder {
|
||||
this.systemShell = systemShell
|
||||
return this
|
||||
}
|
||||
|
||||
fun create(context: Context): ShellTermSession {
|
||||
val cwd = this.cwd ?: NeoTermPath.HOME_PATH
|
||||
|
||||
var shell = this.shell ?:
|
||||
if (systemShell)
|
||||
"/system/bin/sh"
|
||||
else
|
||||
NeoTermPath.USR_PATH + "/bin/" + NeoPreference.loadString(R.string.key_general_shell, "sh")
|
||||
|
||||
if (!File(shell).exists()) {
|
||||
Toast.makeText(context, context.getString(R.string.shell_not_found, shell), Toast.LENGTH_LONG).show()
|
||||
shell = NeoTermPath.USR_PATH + "/bin/sh"
|
||||
}
|
||||
|
||||
val args = this.args ?: mutableListOf(shell)
|
||||
val env = transformEnvironment(this.env) ?: buildEnvironment(cwd, systemShell, shell)
|
||||
val callback = changeCallback ?: TermSessionCallback()
|
||||
return ShellTermSession(shell, cwd, args.toTypedArray(), env, callback)
|
||||
}
|
||||
|
||||
private fun transformEnvironment(env: MutableList<Pair<String, String>>?): Array<String>? {
|
||||
if (env == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
val result = mutableListOf<String>()
|
||||
env.mapTo(result, { "${it.first}=${it.second}" })
|
||||
return result.toTypedArray()
|
||||
}
|
||||
|
||||
|
||||
private fun buildEnvironment(cwd: String?, systemShell: Boolean, executablePath: String): Array<String> {
|
||||
var cwd = cwd
|
||||
File(NeoTermPath.HOME_PATH).mkdirs()
|
||||
|
||||
if (cwd == null) cwd = NeoTermPath.HOME_PATH
|
||||
|
||||
val termEnv = "TERM=xterm-256color"
|
||||
val homeEnv = "HOME=" + NeoTermPath.HOME_PATH
|
||||
val androidRootEnv = "ANDROID_ROOT=" + System.getenv("ANDROID_ROOT")
|
||||
val androidDataEnv = "ANDROID_DATA=" + System.getenv("ANDROID_DATA")
|
||||
val externalStorageEnv = "EXTERNAL_STORAGE=" + System.getenv("EXTERNAL_STORAGE")
|
||||
|
||||
if (systemShell) {
|
||||
val pathEnv = "PATH=" + System.getenv("PATH")
|
||||
return arrayOf(termEnv, homeEnv, androidRootEnv, androidDataEnv, externalStorageEnv, pathEnv)
|
||||
|
||||
} else {
|
||||
val ps1Env = "PS1=$ "
|
||||
val langEnv = "LANG=en_US.UTF-8"
|
||||
val pathEnv = "PATH=" + buildPathEnv()
|
||||
val ldEnv = "LD_LIBRARY_PATH=" + buildLdLibraryEnv()
|
||||
val pwdEnv = "PWD=" + cwd
|
||||
val tmpdirEnv = "TMPDIR=${NeoTermPath.USR_PATH}/tmp"
|
||||
|
||||
return arrayOf(termEnv, homeEnv, ps1Env, ldEnv, langEnv, pathEnv, pwdEnv, androidRootEnv, androidDataEnv, externalStorageEnv, tmpdirEnv)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildLdLibraryEnv(): String {
|
||||
val builder = StringBuilder("${NeoTermPath.USR_PATH}/lib")
|
||||
|
||||
val programSelection = NeoPreference.loadString(R.string.key_general_program_selection, NeoPreference.VALUE_NEOTERM_ONLY)
|
||||
val systemPath = System.getenv("LD_LIBRARY_PATH")
|
||||
|
||||
if (programSelection != NeoPreference.VALUE_NEOTERM_ONLY) {
|
||||
builder.append(":$systemPath")
|
||||
}
|
||||
|
||||
return builder.toString()
|
||||
}
|
||||
|
||||
private fun buildPathEnv(): String {
|
||||
val builder = StringBuilder()
|
||||
val programSelection = NeoPreference.loadString(R.string.key_general_program_selection, NeoPreference.VALUE_NEOTERM_ONLY)
|
||||
val basePath = "${NeoTermPath.USR_PATH}/bin:${NeoTermPath.USR_PATH}/bin/applets"
|
||||
val systemPath = System.getenv("PATH")
|
||||
|
||||
when (programSelection) {
|
||||
NeoPreference.VALUE_NEOTERM_ONLY -> {
|
||||
builder.append(basePath)
|
||||
}
|
||||
NeoPreference.VALUE_NEOTERM_FIRST -> {
|
||||
builder.append("$basePath:$systemPath")
|
||||
}
|
||||
NeoPreference.VALUE_SYSTEM_FIRST -> {
|
||||
builder.append("$systemPath:$basePath")
|
||||
}
|
||||
}
|
||||
return builder.toString()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package io.neoterm.ui.term.tab
|
||||
package io.neoterm.terminal.client
|
||||
|
||||
import android.util.Log
|
||||
import android.view.KeyEvent
|
@ -0,0 +1,47 @@
|
||||
package io.neoterm.terminal.client
|
||||
|
||||
import io.neoterm.backend.TerminalSession
|
||||
import io.neoterm.view.ExtraKeysView
|
||||
import io.neoterm.view.OnAutoCompleteListener
|
||||
import io.neoterm.view.TerminalView
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class TermDataHolder {
|
||||
var termSession: TerminalSession? = null
|
||||
var sessionCallback: TermSessionCallback? = null
|
||||
var viewClient: TermViewClient? = null
|
||||
var onAutoCompleteListener: OnAutoCompleteListener? = null
|
||||
|
||||
var termUI: TermUiPresenter? = null
|
||||
var termView: TerminalView? = null
|
||||
var extraKeysView: ExtraKeysView? = null
|
||||
|
||||
fun cleanup() {
|
||||
onAutoCompleteListener?.onCleanUp()
|
||||
onAutoCompleteListener = null
|
||||
|
||||
sessionCallback?.termData = null
|
||||
viewClient?.termData = null
|
||||
|
||||
termUI = null
|
||||
termView = null
|
||||
extraKeysView = null
|
||||
termSession = null
|
||||
}
|
||||
|
||||
fun initializeSessionWith(session: TerminalSession, sessionCallback: TermSessionCallback?, viewClient: TermViewClient?) {
|
||||
this.termSession = session
|
||||
this.sessionCallback = sessionCallback
|
||||
this.viewClient = viewClient
|
||||
sessionCallback?.termData = this
|
||||
viewClient?.termData = this
|
||||
}
|
||||
|
||||
fun initializeViewWith(termUI: TermUiPresenter?, termView: TerminalView?, eks: ExtraKeysView?) {
|
||||
this.termUI = termUI
|
||||
this.termView = termView
|
||||
this.extraKeysView = eks
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package io.neoterm.ui.term.tab
|
||||
package io.neoterm.terminal.client
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
@ -8,43 +8,40 @@ import android.os.Vibrator
|
||||
import io.neoterm.R
|
||||
import io.neoterm.backend.TerminalSession
|
||||
import io.neoterm.preference.NeoPreference
|
||||
import io.neoterm.view.TerminalView
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class TermSessionCallback : TerminalSession.SessionChangedCallback {
|
||||
var termView: TerminalView? = null
|
||||
var termTab: TermTab? = null
|
||||
var termData: TermDataHolder? = null
|
||||
|
||||
var bellId: Int = 0
|
||||
var soundPool: SoundPool? = null
|
||||
|
||||
override fun onTextChanged(changedSession: TerminalSession?) {
|
||||
termView?.onScreenUpdated()
|
||||
termData?.termView?.onScreenUpdated()
|
||||
}
|
||||
|
||||
override fun onTitleChanged(changedSession: TerminalSession?) {
|
||||
if (changedSession?.title != null) {
|
||||
termTab?.updateTitle(changedSession.title)
|
||||
termData?.termUI?.requireUpdateTitle(changedSession.title)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSessionFinished(finishedSession: TerminalSession?) {
|
||||
termTab?.onSessionFinished()
|
||||
termData?.termUI?.requireOnSessionFinished()
|
||||
}
|
||||
|
||||
override fun onClipboardText(session: TerminalSession?, text: String?) {
|
||||
val termView = termData?.termView
|
||||
if (termView != null) {
|
||||
val clipboard = termView!!.context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clipboard = termView.context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
clipboard.primaryClip = ClipData.newPlainText("", text)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBell(session: TerminalSession?) {
|
||||
if (termView == null) {
|
||||
return
|
||||
}
|
||||
val termView = termData?.termView ?: return
|
||||
|
||||
if (NeoPreference.loadBoolean(R.string.key_general_bell, false)) {
|
||||
if (soundPool == null) {
|
||||
@ -61,8 +58,9 @@ class TermSessionCallback : TerminalSession.SessionChangedCallback {
|
||||
}
|
||||
|
||||
override fun onColorsChanged(session: TerminalSession?) {
|
||||
if (session != null) {
|
||||
termView?.onScreenUpdated()
|
||||
val termView = termData?.termView
|
||||
if (session != null && termView != null) {
|
||||
termView.onScreenUpdated()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package io.neoterm.terminal.client
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
interface TermUiPresenter {
|
||||
fun requireClose()
|
||||
fun requireToggleFullScreen()
|
||||
fun requirePaste()
|
||||
fun requireUpdateTitle(title: String?)
|
||||
fun requireOnSessionFinished()
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package io.neoterm.ui.term.tab
|
||||
package io.neoterm.terminal.client
|
||||
|
||||
import android.content.Context
|
||||
import android.media.AudioManager
|
||||
@ -11,8 +11,6 @@ import io.neoterm.backend.KeyHandler
|
||||
import io.neoterm.backend.TerminalSession
|
||||
import io.neoterm.customize.eks.EksKeysManager
|
||||
import io.neoterm.preference.NeoPreference
|
||||
import io.neoterm.view.ExtraKeysView
|
||||
import io.neoterm.view.TerminalView
|
||||
import io.neoterm.view.TerminalViewClient
|
||||
|
||||
|
||||
@ -26,9 +24,7 @@ class TermViewClient(val context: Context) : TerminalViewClient {
|
||||
|
||||
var sessionFinished: Boolean = false
|
||||
|
||||
var termTab: TermTab? = null
|
||||
var termView: TerminalView? = null
|
||||
var extraKeysView: ExtraKeysView? = null
|
||||
var termData: TermDataHolder? = null
|
||||
|
||||
override fun onScale(scale: Float): Float {
|
||||
if (scale < 0.9f || scale > 1.1f) {
|
||||
@ -40,9 +36,12 @@ class TermViewClient(val context: Context) : TerminalViewClient {
|
||||
}
|
||||
|
||||
override fun onSingleTapUp(e: MotionEvent?) {
|
||||
val termView = termData?.termView
|
||||
if (termView != null) {
|
||||
(context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager)
|
||||
.showSoftInput(termView, InputMethodManager.SHOW_IMPLICIT)
|
||||
}
|
||||
}
|
||||
|
||||
override fun shouldBackButtonBeMappedToEscape(): Boolean {
|
||||
return NeoPreference.loadBoolean(R.string.key_generaL_backspace_map_to_esc, false)
|
||||
@ -53,10 +52,12 @@ class TermViewClient(val context: Context) : TerminalViewClient {
|
||||
}
|
||||
|
||||
override fun onKeyDown(keyCode: Int, e: KeyEvent?, session: TerminalSession?): Boolean {
|
||||
val termUI = termData?.termUI
|
||||
|
||||
when (keyCode) {
|
||||
KeyEvent.KEYCODE_ENTER -> {
|
||||
if (e?.action == KeyEvent.ACTION_DOWN && sessionFinished) {
|
||||
termTab?.requireCloseTab()
|
||||
termUI?.requireClose()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@ -67,9 +68,9 @@ class TermViewClient(val context: Context) : TerminalViewClient {
|
||||
val unicodeChar = e.getUnicodeChar(0).toChar()
|
||||
|
||||
if (unicodeChar == 'f'/* full screen */) {
|
||||
termTab?.requireToggleFullScreen()
|
||||
termUI?.requireToggleFullScreen()
|
||||
} else if (unicodeChar == 'v') {
|
||||
termTab?.requirePaste()
|
||||
termUI?.requirePaste()
|
||||
} else if (unicodeChar == '+' || e.getUnicodeChar(KeyEvent.META_SHIFT_ON).toChar() == '+') {
|
||||
// We also check for the shifted char here since shift may be required to produce '+',
|
||||
// see https://github.com/termux/termux-api/issues/2
|
||||
@ -86,11 +87,13 @@ class TermViewClient(val context: Context) : TerminalViewClient {
|
||||
}
|
||||
|
||||
override fun readControlKey(): Boolean {
|
||||
return (extraKeysView != null && extraKeysView!!.readControlButton()) || mVirtualControlKeyDown
|
||||
val extraKeysView = termData?.extraKeysView
|
||||
return (extraKeysView != null && extraKeysView.readControlButton()) || mVirtualControlKeyDown
|
||||
}
|
||||
|
||||
override fun readAltKey(): Boolean {
|
||||
return (extraKeysView != null && extraKeysView!!.readAltButton()) || mVirtualFnKeyDown
|
||||
val extraKeysView = termData?.extraKeysView
|
||||
return (extraKeysView != null && extraKeysView.readAltButton()) || mVirtualFnKeyDown
|
||||
}
|
||||
|
||||
override fun onCodePoint(codePoint: Int, ctrlDown: Boolean, session: TerminalSession?): Boolean {
|
||||
@ -179,6 +182,8 @@ class TermViewClient(val context: Context) : TerminalViewClient {
|
||||
}
|
||||
|
||||
fun updateSuggestions(title: String?, force: Boolean = false) {
|
||||
val extraKeysView = termData?.extraKeysView
|
||||
|
||||
if (extraKeysView == null || title == null || title.isEmpty()) {
|
||||
return
|
||||
}
|
||||
@ -192,13 +197,17 @@ class TermViewClient(val context: Context) : TerminalViewClient {
|
||||
}
|
||||
|
||||
fun removeSuggestions() {
|
||||
val extraKeysView = termData?.extraKeysView
|
||||
extraKeysView?.clearUserDefinedButton()
|
||||
}
|
||||
|
||||
private fun changeFontSize(increase: Boolean) {
|
||||
val termView = termData?.termView
|
||||
if (termView != null) {
|
||||
val changedSize = (if (increase) 1 else -1) * 2
|
||||
val fontSize = termView!!.textSize + changedSize
|
||||
termView!!.textSize = fontSize
|
||||
val fontSize = termView.textSize + changedSize
|
||||
termView.textSize = fontSize
|
||||
NeoPreference.store(NeoPreference.KEY_FONT_SIZE, fontSize)
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@ package io.neoterm.ui.customization
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.graphics.Typeface
|
||||
import android.os.Bundle
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.support.v7.widget.Toolbar
|
||||
@ -57,7 +56,7 @@ class CustomizationActivity : AppCompatActivity() {
|
||||
viewClient = BasicViewClient(terminalView)
|
||||
sessionCallback = BasicSessionCallback(terminalView)
|
||||
TerminalUtils.setupTerminalView(terminalView, viewClient)
|
||||
session = TerminalUtils.createSession(this, "${NeoTermPath.USR_PATH}/bin/applets/echo",
|
||||
session = TerminalUtils.createShellSession(this, "${NeoTermPath.USR_PATH}/bin/applets/echo",
|
||||
arrayOf("echo", "Hello NeoTerm."), null, null, null, sessionCallback, false)
|
||||
terminalView.attachSession(session)
|
||||
|
||||
|
@ -97,6 +97,7 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
|
||||
dialog.setTitle(getString(R.string.done))
|
||||
}
|
||||
})
|
||||
.imeEnabled(true)
|
||||
.show("Installing $packageName")
|
||||
}
|
||||
}
|
||||
@ -185,6 +186,7 @@ class PackageManagerActivity : AppCompatActivity(), SearchView.OnQueryTextListen
|
||||
}
|
||||
})
|
||||
.execute(NeoTermPath.APT_BIN_PATH, arrayOf("apt", "update"))
|
||||
.imeEnabled(true)
|
||||
.show("apt update")
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,6 @@ import android.os.Bundle
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.Toast
|
||||
import com.igalata.bubblepicker.BubblePickerListener
|
||||
@ -22,6 +21,7 @@ import io.neoterm.customize.setup.BaseFileInstaller
|
||||
import io.neoterm.preference.NeoPreference
|
||||
import io.neoterm.preference.NeoTermPath
|
||||
import io.neoterm.utils.PackageUtils
|
||||
import io.neoterm.utils.TerminalUtils
|
||||
import io.neoterm.view.TerminalDialog
|
||||
import java.util.*
|
||||
|
||||
@ -38,7 +38,6 @@ class SetupActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
lateinit var picker: BubblePicker
|
||||
lateinit var nextButton: Button
|
||||
lateinit var toast: Toast
|
||||
var aptUpdated = false
|
||||
|
||||
@ -46,7 +45,7 @@ class SetupActivity : AppCompatActivity() {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.ui_setup)
|
||||
picker = findViewById(R.id.bubble_picker) as BubblePicker
|
||||
nextButton = findViewById(R.id.setup_next) as Button
|
||||
val nextButton = findViewById(R.id.setup_next) as Button
|
||||
nextButton.setOnClickListener {
|
||||
if (aptUpdated) {
|
||||
val packageList = mutableListOf("apt", "install", "-y")
|
||||
@ -101,7 +100,6 @@ class SetupActivity : AppCompatActivity() {
|
||||
.setMessage(error.toString())
|
||||
.setNegativeButton(R.string.use_system_shell, { _, _ ->
|
||||
setResult(Activity.RESULT_CANCELED)
|
||||
nextButton.visibility = View.VISIBLE
|
||||
finish()
|
||||
})
|
||||
.setPositiveButton(R.string.retry, { dialog, _ ->
|
||||
@ -114,21 +112,25 @@ class SetupActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun executeAptUpdate() {
|
||||
TerminalDialog(this)
|
||||
.onFinish(object : TerminalDialog.SessionFinishedCallback {
|
||||
override fun onSessionFinished(dialog: TerminalDialog, finishedSession: TerminalSession?) {
|
||||
nextButton.visibility = View.VISIBLE
|
||||
val exit = finishedSession?.exitStatus ?: 1
|
||||
if (exit == 0) {
|
||||
TerminalUtils.executeApt(this, "update", { exitStatus, dialog ->
|
||||
if (exitStatus == 0) {
|
||||
dialog.dismiss()
|
||||
aptUpdated = true
|
||||
executeAptUpgrade()
|
||||
} else {
|
||||
dialog.setTitle(getString(R.string.error))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun executeAptUpgrade() {
|
||||
TerminalUtils.executeApt(this, "upgrade", { exitStatus, dialog ->
|
||||
if (exitStatus == 0) {
|
||||
dialog.dismiss()
|
||||
} else {
|
||||
dialog.setTitle(getString(R.string.error))
|
||||
}
|
||||
})
|
||||
.execute(NeoTermPath.APT_BIN_PATH, arrayOf("apt", "update"))
|
||||
.show("apt update")
|
||||
}
|
||||
|
||||
@SuppressLint("ShowToast")
|
||||
|
@ -33,10 +33,10 @@ import io.neoterm.ui.bonus.BonusActivity
|
||||
import io.neoterm.ui.pm.PackageManagerActivity
|
||||
import io.neoterm.ui.settings.SettingActivity
|
||||
import io.neoterm.ui.setup.SetupActivity
|
||||
import io.neoterm.ui.term.tab.TermSessionCallback
|
||||
import io.neoterm.terminal.client.TermSessionCallback
|
||||
import io.neoterm.ui.term.tab.TermTab
|
||||
import io.neoterm.ui.term.tab.TermTabDecorator
|
||||
import io.neoterm.ui.term.tab.TermViewClient
|
||||
import io.neoterm.terminal.client.TermViewClient
|
||||
import io.neoterm.ui.term.tab.event.TabCloseEvent
|
||||
import io.neoterm.ui.term.tab.event.TitleChangedEvent
|
||||
import io.neoterm.ui.term.tab.event.ToggleFullScreenEvent
|
||||
@ -189,8 +189,8 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
}
|
||||
|
||||
override fun onSelectionChanged(tabSwitcher: TabSwitcher, selectedTabIndex: Int, selectedTab: Tab?) {
|
||||
if (selectedTab is TermTab && selectedTab.termSession != null) {
|
||||
NeoPreference.storeCurrentSession(selectedTab.termSession!!)
|
||||
if (selectedTab is TermTab && selectedTab.termData.termSession != null) {
|
||||
NeoPreference.storeCurrentSession(selectedTab.termData.termSession!!)
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,8 +199,8 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
|
||||
override fun onTabRemoved(tabSwitcher: TabSwitcher, index: Int, tab: Tab, animation: Animation) {
|
||||
if (tab is TermTab) {
|
||||
tab.termSession?.finishIfRunning()
|
||||
removeFinishedSession(tab.termSession)
|
||||
tab.termData.termSession?.finishIfRunning()
|
||||
removeFinishedSession(tab.termData.termSession)
|
||||
tab.cleanup()
|
||||
}
|
||||
}
|
||||
@ -387,29 +387,32 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
val tabCount = tabSwitcher.count
|
||||
(0..(tabCount - 1))
|
||||
.map { tabSwitcher.getTab(it) }
|
||||
.filter { it is TermTab && it.termSession == session }
|
||||
.filter { it is TermTab && it.termData.termSession == session }
|
||||
.forEach { return }
|
||||
|
||||
val sessionCallback = session.sessionChangedCallback as TermSessionCallback
|
||||
val viewClient = TermViewClient(this)
|
||||
|
||||
val tab = createTab(session.title) as TermTab
|
||||
tab.sessionCallback = session.sessionChangedCallback as TermSessionCallback
|
||||
tab.viewClient = TermViewClient(this)
|
||||
tab.termSession = session
|
||||
tab.termData.initializeSessionWith(session, sessionCallback, viewClient)
|
||||
|
||||
addNewTab(tab, createRevealAnimation())
|
||||
switchToSession(tab)
|
||||
}
|
||||
|
||||
private fun addNewSession(sessionName: String?, systemShell: Boolean, animation: Animation) {
|
||||
val tab = createTab(sessionName) as TermTab
|
||||
tab.sessionCallback = TermSessionCallback()
|
||||
tab.viewClient = TermViewClient(this)
|
||||
tab.termSession = termService!!.createTermSession(null, null,
|
||||
null, null, null, tab.sessionCallback, systemShell)
|
||||
val sessionCallback = TermSessionCallback()
|
||||
val viewClient = TermViewClient(this)
|
||||
val session = termService!!.createTermSession(null, null,
|
||||
null, null, null, sessionCallback, systemShell)
|
||||
|
||||
if (sessionName != null) {
|
||||
tab.termSession!!.mSessionName = sessionName
|
||||
session.mSessionName = sessionName
|
||||
}
|
||||
|
||||
val tab = createTab(sessionName) as TermTab
|
||||
tab.termData.initializeSessionWith(session, sessionCallback, viewClient)
|
||||
|
||||
addNewTab(tab, animation)
|
||||
switchToSession(tab)
|
||||
}
|
||||
@ -421,7 +424,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
|
||||
|
||||
for (i in 0..tabSwitcher.count - 1) {
|
||||
val tab = tabSwitcher.getTab(i)
|
||||
if (tab is TermTab && tab.termSession == session) {
|
||||
if (tab is TermTab && tab.termData.termSession == session) {
|
||||
switchToSession(tab)
|
||||
break
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import io.neoterm.customize.script.UserScript
|
||||
import io.neoterm.customize.script.UserScriptManager
|
||||
import io.neoterm.preference.NeoPreference
|
||||
import io.neoterm.services.NeoTermService
|
||||
import io.neoterm.ui.term.tab.TermSessionCallback
|
||||
import io.neoterm.terminal.client.TermSessionCallback
|
||||
import io.neoterm.utils.TerminalUtils
|
||||
import java.io.File
|
||||
|
||||
|
@ -5,58 +5,31 @@ import android.support.v7.widget.Toolbar
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import de.mrapp.android.tabswitcher.Tab
|
||||
import io.neoterm.R
|
||||
import io.neoterm.backend.TerminalSession
|
||||
import io.neoterm.customize.color.ColorSchemeManager
|
||||
import io.neoterm.preference.NeoPreference
|
||||
import io.neoterm.terminal.client.TermDataHolder
|
||||
import io.neoterm.terminal.client.TermUiPresenter
|
||||
import io.neoterm.ui.term.tab.event.TabCloseEvent
|
||||
import io.neoterm.ui.term.tab.event.TitleChangedEvent
|
||||
import io.neoterm.ui.term.tab.event.ToggleFullScreenEvent
|
||||
import io.neoterm.view.OnAutoCompleteListener
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
|
||||
class TermTab(title: CharSequence) : Tab(title) {
|
||||
var termSession: TerminalSession? = null
|
||||
var sessionCallback: TermSessionCallback? = null
|
||||
var viewClient: TermViewClient? = null
|
||||
var onAutoCompleteListener: OnAutoCompleteListener? = null
|
||||
class TermTab(title: CharSequence) : Tab(title), TermUiPresenter {
|
||||
var termData = TermDataHolder()
|
||||
var toolbar: Toolbar? = null
|
||||
|
||||
fun updateColorScheme() {
|
||||
ColorSchemeManager.applyColorScheme(viewClient?.termView, viewClient?.extraKeysView,
|
||||
ColorSchemeManager.applyColorScheme(termData.termView, termData.extraKeysView,
|
||||
ColorSchemeManager.getCurrentColorScheme())
|
||||
}
|
||||
|
||||
fun cleanup() {
|
||||
onAutoCompleteListener?.onCleanUp()
|
||||
onAutoCompleteListener = null
|
||||
|
||||
viewClient?.termTab = null
|
||||
viewClient?.termView = null
|
||||
viewClient?.extraKeysView = null
|
||||
sessionCallback?.termView = null
|
||||
sessionCallback?.termTab = null
|
||||
termData.cleanup()
|
||||
toolbar = null
|
||||
termSession = null
|
||||
}
|
||||
|
||||
fun updateTitle(title: String) {
|
||||
if (title.isNotEmpty()) {
|
||||
this.title = title
|
||||
EventBus.getDefault().post(TitleChangedEvent(title))
|
||||
if (NeoPreference.loadBoolean(R.string.key_ui_suggestions, true)) {
|
||||
viewClient?.updateSuggestions(title)
|
||||
} else {
|
||||
viewClient?.removeSuggestions()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onSessionFinished() {
|
||||
viewClient?.sessionFinished = true
|
||||
}
|
||||
|
||||
fun onFullScreenModeChanged(fullScreen: Boolean) {
|
||||
@ -64,13 +37,8 @@ class TermTab(title: CharSequence) : Tab(title) {
|
||||
resetAutoCompleteStatus()
|
||||
}
|
||||
|
||||
fun requireCloseTab() {
|
||||
requireHideIme()
|
||||
EventBus.getDefault().post(TabCloseEvent(this))
|
||||
}
|
||||
|
||||
fun requireHideIme() {
|
||||
val terminalView = viewClient?.termView
|
||||
val terminalView = termData.termView
|
||||
if (terminalView != null) {
|
||||
val imm = terminalView.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
if (imm.isActive) {
|
||||
@ -79,16 +47,37 @@ class TermTab(title: CharSequence) : Tab(title) {
|
||||
}
|
||||
}
|
||||
|
||||
fun requireToggleFullScreen() {
|
||||
override fun requireToggleFullScreen() {
|
||||
EventBus.getDefault().post(ToggleFullScreenEvent())
|
||||
}
|
||||
|
||||
fun requirePaste() {
|
||||
viewClient?.termView?.pasteFromClipboard()
|
||||
override fun requirePaste() {
|
||||
termData.termView?.pasteFromClipboard()
|
||||
}
|
||||
|
||||
override fun requireClose() {
|
||||
requireHideIme()
|
||||
EventBus.getDefault().post(TabCloseEvent(this))
|
||||
}
|
||||
|
||||
override fun requireUpdateTitle(title: String?) {
|
||||
if (title != null && title.isNotEmpty()) {
|
||||
this.title = title
|
||||
EventBus.getDefault().post(TitleChangedEvent(title))
|
||||
if (NeoPreference.loadBoolean(R.string.key_ui_suggestions, true)) {
|
||||
termData.viewClient?.updateSuggestions(title)
|
||||
} else {
|
||||
termData.viewClient?.removeSuggestions()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun requireOnSessionFinished() {
|
||||
termData.viewClient?.sessionFinished = true
|
||||
}
|
||||
|
||||
fun resetAutoCompleteStatus() {
|
||||
onAutoCompleteListener?.onCleanUp()
|
||||
onAutoCompleteListener = null
|
||||
termData.onAutoCompleteListener?.onCleanUp()
|
||||
termData.onAutoCompleteListener = null
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import io.neoterm.BuildConfig
|
||||
import io.neoterm.R
|
||||
import io.neoterm.customize.color.ColorSchemeManager
|
||||
import io.neoterm.preference.NeoPreference
|
||||
import io.neoterm.terminal.client.TermCompleteListener
|
||||
import io.neoterm.ui.term.NeoTermActivity
|
||||
import io.neoterm.utils.TerminalUtils
|
||||
import io.neoterm.view.ExtraKeysView
|
||||
@ -58,32 +59,27 @@ class TermTabDecorator(val context: NeoTermActivity) : TabSwitcherDecorator() {
|
||||
|
||||
if (tab is TermTab) {
|
||||
val termTab = tab
|
||||
val termData = tab.termData
|
||||
|
||||
TerminalUtils.setupTerminalSession(termTab.termSession)
|
||||
TerminalUtils.setupTerminalSession(termData.termSession)
|
||||
|
||||
// 复用前一次的 TermSessionCallback
|
||||
termTab.sessionCallback?.termView = view
|
||||
termTab.sessionCallback?.termTab = termTab
|
||||
// 复用前一次的 TermSessionCallback 和 TermViewClient
|
||||
termData.initializeViewWith(termTab, view, extraKeysView)
|
||||
|
||||
// 复用上一次的 TermViewClient
|
||||
termTab.viewClient?.termTab = termTab
|
||||
termTab.viewClient?.termView = view
|
||||
termTab.viewClient?.extraKeysView = extraKeysView
|
||||
|
||||
if (termTab.termSession != null) {
|
||||
termTab.viewClient?.updateSuggestions(termTab.termSession?.title, true)
|
||||
if (termData.termSession != null) {
|
||||
termData.viewClient?.updateSuggestions(termData.termSession?.title, true)
|
||||
}
|
||||
|
||||
view.setTerminalViewClient(termTab.viewClient)
|
||||
view.attachSession(termTab.termSession)
|
||||
view.setTerminalViewClient(termData.viewClient)
|
||||
view.attachSession(termData.termSession)
|
||||
|
||||
// Still in progress
|
||||
// Only available for developers.
|
||||
if (BuildConfig.DEBUG) {
|
||||
if (termTab.onAutoCompleteListener == null) {
|
||||
termTab.onAutoCompleteListener = createAutoCompleteListener(view)
|
||||
if (termData.onAutoCompleteListener == null) {
|
||||
termData.onAutoCompleteListener = createAutoCompleteListener(view)
|
||||
}
|
||||
view.onAutoCompleteListener = termTab.onAutoCompleteListener
|
||||
view.onAutoCompleteListener = termData.onAutoCompleteListener
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,22 @@
|
||||
package io.neoterm.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.Toast
|
||||
import io.neoterm.R
|
||||
import io.neoterm.backend.TerminalSession
|
||||
import io.neoterm.customize.font.FontManager
|
||||
import io.neoterm.preference.NeoPreference
|
||||
import io.neoterm.preference.NeoTermPath
|
||||
import io.neoterm.view.BasicViewClient
|
||||
import io.neoterm.terminal.ShellTermSession
|
||||
import io.neoterm.view.ExtraKeysView
|
||||
import io.neoterm.view.TerminalDialog
|
||||
import io.neoterm.view.TerminalView
|
||||
import java.io.File
|
||||
import io.neoterm.view.TerminalViewClient
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
object TerminalUtils {
|
||||
fun setupTerminalView(terminalView: TerminalView?, terminalViewClient: BasicViewClient? = null) {
|
||||
fun setupTerminalView(terminalView: TerminalView?, terminalViewClient: TerminalViewClient? = null) {
|
||||
terminalView?.textSize = NeoPreference.loadInt(NeoPreference.KEY_FONT_SIZE, 30)
|
||||
terminalView?.setTypeface(FontManager.getCurrentFont().getTypeFace())
|
||||
if (terminalViewClient != null) {
|
||||
@ -31,44 +31,23 @@ object TerminalUtils {
|
||||
fun setupTerminalSession(session: TerminalSession?) {
|
||||
}
|
||||
|
||||
fun createSession(context: Context, executablePath: String?, arguments: Array<String>?,
|
||||
cwd: String?, initialCommand: String?, env: Array<String>?,
|
||||
fun createShellSession(context: Context, executablePath: String?, arguments: Array<String>?,
|
||||
cwd: String?, initialCommand: String?, env: Array<Pair<String, String>>?,
|
||||
sessionCallback: TerminalSession.SessionChangedCallback?,
|
||||
systemShell: Boolean): TerminalSession {
|
||||
val initCommand = initialCommand ?:
|
||||
NeoPreference.loadString(R.string.key_general_initial_command, "")
|
||||
|
||||
var executablePath = executablePath
|
||||
var arguments = arguments
|
||||
var initialCommand = initialCommand
|
||||
var cwd = cwd
|
||||
|
||||
if (cwd == null) {
|
||||
cwd = NeoTermPath.HOME_PATH
|
||||
}
|
||||
|
||||
if (executablePath == null) {
|
||||
executablePath = if (systemShell)
|
||||
"/system/bin/sh"
|
||||
else
|
||||
NeoTermPath.USR_PATH + "/bin/" + NeoPreference.loadString(R.string.key_general_shell, "sh")
|
||||
|
||||
if (!File(executablePath).exists()) {
|
||||
Toast.makeText(context, context.getString(R.string.shell_not_found, executablePath), Toast.LENGTH_LONG).show()
|
||||
executablePath = NeoTermPath.USR_PATH + "/bin/sh"
|
||||
}
|
||||
}
|
||||
|
||||
if (arguments == null) {
|
||||
arguments = arrayOf<String>(executablePath)
|
||||
}
|
||||
|
||||
if (initialCommand == null) {
|
||||
initialCommand = NeoPreference.loadString(R.string.key_general_initial_command, "")
|
||||
}
|
||||
|
||||
val session = TerminalSession(executablePath, cwd, initialCommand, arguments,
|
||||
env ?: NeoPreference.buildEnvironment(cwd, systemShell, executablePath),
|
||||
sessionCallback)
|
||||
val session = ShellTermSession.Builder()
|
||||
.shell(executablePath)
|
||||
.currentWorkingDirectory(cwd)
|
||||
.callback(sessionCallback)
|
||||
.systemShell(systemShell)
|
||||
.envArray(env)
|
||||
.argArray(arguments)
|
||||
.create(context)
|
||||
setupTerminalSession(session)
|
||||
session.initialCommand = initCommand
|
||||
return session
|
||||
}
|
||||
|
||||
@ -91,4 +70,17 @@ object TerminalUtils {
|
||||
builder.append('"')
|
||||
return builder.toString()
|
||||
}
|
||||
|
||||
fun executeApt(context: Context, subCommand: String, callback: (Int, TerminalDialog) -> Unit) {
|
||||
TerminalDialog(context)
|
||||
.onFinish(object : TerminalDialog.SessionFinishedCallback {
|
||||
override fun onSessionFinished(dialog: TerminalDialog, finishedSession: TerminalSession?) {
|
||||
val exit = finishedSession?.exitStatus ?: 1
|
||||
callback(exit, dialog)
|
||||
}
|
||||
})
|
||||
.imeEnabled(true)
|
||||
.execute(NeoTermPath.APT_BIN_PATH, arrayOf("apt", subCommand))
|
||||
.show("apt $subCommand")
|
||||
}
|
||||
}
|
@ -22,7 +22,6 @@ class TerminalDialog(val context: Context) {
|
||||
@SuppressLint("InflateParams")
|
||||
private var view: View = LayoutInflater.from(context).inflate(R.layout.ui_term_dialog, null, false)
|
||||
private var terminalView: TerminalView
|
||||
private var terminalViewClient: BasicViewClient
|
||||
private var terminalSessionCallback: BasicSessionCallback
|
||||
private var dialog: AlertDialog? = null
|
||||
private var terminalSession: TerminalSession? = null
|
||||
@ -31,10 +30,8 @@ class TerminalDialog(val context: Context) {
|
||||
|
||||
init {
|
||||
terminalView = view.findViewById(R.id.terminal_view_dialog) as TerminalView
|
||||
terminalViewClient = BasicViewClient(terminalView)
|
||||
TerminalUtils.setupTerminalView(terminalView, terminalViewClient)
|
||||
TerminalUtils.setupTerminalView(terminalView, BasicViewClient(terminalView))
|
||||
|
||||
terminalView.setTerminalViewClient(terminalViewClient)
|
||||
terminalSessionCallback = object : BasicSessionCallback(terminalView) {
|
||||
override fun onSessionFinished(finishedSession: TerminalSession?) {
|
||||
sessionFinishedCallback?.onSessionFinished(this@TerminalDialog, finishedSession)
|
||||
@ -56,7 +53,7 @@ class TerminalDialog(val context: Context) {
|
||||
}
|
||||
.create()
|
||||
|
||||
terminalSession = TerminalUtils.createSession(context, executablePath, arguments, null, null, null, terminalSessionCallback, false)
|
||||
terminalSession = TerminalUtils.createShellSession(context, executablePath, arguments, null, null, null, terminalSessionCallback, false)
|
||||
terminalView.attachSession(terminalSession)
|
||||
return this
|
||||
}
|
||||
@ -85,4 +82,12 @@ class TerminalDialog(val context: Context) {
|
||||
dialog?.dismiss()
|
||||
return this
|
||||
}
|
||||
|
||||
fun imeEnabled(enabled: Boolean): TerminalDialog {
|
||||
if (enabled) {
|
||||
terminalView.isFocusable = true
|
||||
terminalView.isFocusableInTouchMode = true
|
||||
}
|
||||
return this
|
||||
}
|
||||
}
|
@ -286,7 +286,6 @@ public final class TerminalView extends View {
|
||||
|
||||
@Override
|
||||
public boolean commitText(CharSequence text, int newCursorPosition) {
|
||||
// TODO: AutoComplete
|
||||
if (LOG_KEY_EVENTS) {
|
||||
Log.i(EmulatorDebug.LOG_TAG, "IME: commitText(\"" + text + "\", " + newCursorPosition + ")");
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.0.0-alpha5'
|
||||
classpath 'com.android.tools.build:gradle:3.0.0-alpha7'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
Loading…
x
Reference in New Issue
Block a user