Feature: NeoTerm Runtime
This commit is contained in:
@ -18,6 +18,11 @@ android {
|
|||||||
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
|
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
jniLibs.srcDirs = ['src/main/jniLibs']
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
package="io.neoterm">
|
package="io.neoterm">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
182
app/src/main/java/io/neoterm/installer/BaseFileInstaller.java
Normal file
182
app/src/main/java/io/neoterm/installer/BaseFileInstaller.java
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
package io.neoterm.installer;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.DialogInterface.OnClickListener;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.system.Os;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
|
import io.neoterm.backend.EmulatorDebug;
|
||||||
|
import io.neoterm.preference.NeoTermPreference;
|
||||||
|
|
||||||
|
public final class BaseFileInstaller {
|
||||||
|
|
||||||
|
public static void installBaseFiles(final Activity activity, final Runnable whenDone) {
|
||||||
|
final File PREFIX_FILE = new File(NeoTermPreference.USR_PATH);
|
||||||
|
if (PREFIX_FILE.isDirectory()) {
|
||||||
|
whenDone.run();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ProgressDialog progress = ProgressDialog.show(activity, null, "Installing", true, false);
|
||||||
|
new Thread() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
final String STAGING_PREFIX_PATH = NeoTermPreference.ROOT_PATH + "/usr-staging";
|
||||||
|
final File STAGING_PREFIX_FILE = new File(STAGING_PREFIX_PATH);
|
||||||
|
|
||||||
|
if (STAGING_PREFIX_FILE.exists()) {
|
||||||
|
deleteFolder(STAGING_PREFIX_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
final byte[] buffer = new byte[8096];
|
||||||
|
final List<Pair<String, String>> symlinks = new ArrayList<>(50);
|
||||||
|
|
||||||
|
final URL zipUrl = determineZipUrl();
|
||||||
|
try (ZipInputStream zipInput = new ZipInputStream(zipUrl.openStream())) {
|
||||||
|
ZipEntry zipEntry;
|
||||||
|
while ((zipEntry = zipInput.getNextEntry()) != null) {
|
||||||
|
if (zipEntry.getName().equals("SYMLINKS.txt")) {
|
||||||
|
BufferedReader symlinksReader = new BufferedReader(new InputStreamReader(zipInput));
|
||||||
|
String line;
|
||||||
|
while ((line = symlinksReader.readLine()) != null) {
|
||||||
|
if (line.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String[] parts = line.split("←");
|
||||||
|
if (parts.length != 2)
|
||||||
|
throw new RuntimeException("Malformed symlink line: " + line);
|
||||||
|
String oldPath = parts[0];
|
||||||
|
String newPath = STAGING_PREFIX_PATH + "/" + parts[1];
|
||||||
|
symlinks.add(Pair.create(oldPath, newPath));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String zipEntryName = zipEntry.getName();
|
||||||
|
File targetFile = new File(STAGING_PREFIX_PATH, zipEntryName);
|
||||||
|
if (zipEntry.isDirectory()) {
|
||||||
|
if (!targetFile.mkdirs())
|
||||||
|
throw new RuntimeException("Failed to create directory: " + targetFile.getAbsolutePath());
|
||||||
|
} else {
|
||||||
|
try (FileOutputStream outStream = new FileOutputStream(targetFile)) {
|
||||||
|
int readBytes;
|
||||||
|
while ((readBytes = zipInput.read(buffer)) != -1)
|
||||||
|
outStream.write(buffer, 0, readBytes);
|
||||||
|
}
|
||||||
|
if (zipEntryName.startsWith("bin/") || zipEntryName.startsWith("libexec") || zipEntryName.startsWith("lib/apt/methods")) {
|
||||||
|
//noinspection OctalInteger
|
||||||
|
Os.chmod(targetFile.getAbsolutePath(), 0700);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symlinks.isEmpty())
|
||||||
|
throw new RuntimeException("No SYMLINKS.txt encountered");
|
||||||
|
for (Pair<String, String> symlink : symlinks) {
|
||||||
|
Os.symlink(symlink.first, symlink.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!STAGING_PREFIX_FILE.renameTo(PREFIX_FILE)) {
|
||||||
|
throw new RuntimeException("Unable to rename staging folder");
|
||||||
|
}
|
||||||
|
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
whenDone.run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (final Exception e) {
|
||||||
|
Log.e(EmulatorDebug.LOG_TAG, "Bootstrap error", e);
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
new AlertDialog.Builder(activity).setTitle("ERROR").setMessage(e.toString())
|
||||||
|
.setNegativeButton("Abort", new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
dialog.dismiss();
|
||||||
|
activity.finish();
|
||||||
|
}
|
||||||
|
}).setPositiveButton("Retry", new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
dialog.dismiss();
|
||||||
|
BaseFileInstaller.installBaseFiles(activity, whenDone);
|
||||||
|
}
|
||||||
|
}).show();
|
||||||
|
} catch (WindowManager.BadTokenException e) {
|
||||||
|
// Activity already dismissed - ignore.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
progress.dismiss();
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
// Activity already dismissed - ignore.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static URL determineZipUrl() throws MalformedURLException {
|
||||||
|
String archName = determineArchName();
|
||||||
|
return new URL("https://kernel19.cc/neoterm/boot/" + archName + ".zip");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String determineArchName() {
|
||||||
|
for (String androidArch : Build.SUPPORTED_ABIS) {
|
||||||
|
switch (androidArch) {
|
||||||
|
case "arm64-v8a":
|
||||||
|
return "aarch64";
|
||||||
|
case "armeabi-v7a":
|
||||||
|
return "arm";
|
||||||
|
case "x86_64":
|
||||||
|
return "x86_64";
|
||||||
|
case "x86":
|
||||||
|
return "i686";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Unable to determine arch from Build.SUPPORTED_ABIS = " +
|
||||||
|
Arrays.toString(Build.SUPPORTED_ABIS));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void deleteFolder(File fileOrDirectory) {
|
||||||
|
File[] children = fileOrDirectory.listFiles();
|
||||||
|
if (children != null) {
|
||||||
|
for (File child : children) {
|
||||||
|
deleteFolder(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!fileOrDirectory.delete()) {
|
||||||
|
throw new RuntimeException("Unable to delete " + (fileOrDirectory.isDirectory() ? "directory " : "file ") + fileOrDirectory.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
46
app/src/main/java/io/neoterm/preference/NeoPermission.kt
Normal file
46
app/src/main/java/io/neoterm/preference/NeoPermission.kt
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package io.neoterm.preference
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.AlertDialog
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build
|
||||||
|
import android.support.v4.app.ActivityCompat
|
||||||
|
import android.support.v4.content.ContextCompat
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kiva
|
||||||
|
*/
|
||||||
|
object NeoPermission {
|
||||||
|
const val REQUEST_APP_PERMISSION = 10086
|
||||||
|
|
||||||
|
fun initAppPermission(context: Activity, requestCode: Int) {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ContextCompat.checkSelfPermission(context,
|
||||||
|
Manifest.permission.READ_CONTACTS)
|
||||||
|
!= PackageManager.PERMISSION_GRANTED) {
|
||||||
|
|
||||||
|
if (ActivityCompat.shouldShowRequestPermissionRationale(context,
|
||||||
|
Manifest.permission.READ_CONTACTS)) {
|
||||||
|
AlertDialog.Builder(context).setMessage("需要存储权限来访问存储设备上的文件")
|
||||||
|
.setPositiveButton(android.R.string.ok, { _: DialogInterface, _: Int ->
|
||||||
|
ActivityCompat.requestPermissions(context,
|
||||||
|
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||||
|
Manifest.permission.RECEIVE_BOOT_COMPLETED),
|
||||||
|
requestCode)
|
||||||
|
})
|
||||||
|
.show()
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ActivityCompat.requestPermissions(context,
|
||||||
|
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||||
|
Manifest.permission.RECEIVE_BOOT_COMPLETED),
|
||||||
|
requestCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,12 +5,18 @@ import android.content.SharedPreferences
|
|||||||
import android.preference.PreferenceManager
|
import android.preference.PreferenceManager
|
||||||
import io.neoterm.backend.TerminalSession
|
import io.neoterm.backend.TerminalSession
|
||||||
import io.neoterm.services.NeoTermService
|
import io.neoterm.services.NeoTermService
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kiva
|
* @author kiva
|
||||||
*/
|
*/
|
||||||
|
|
||||||
object NeoTermPreference {
|
object NeoTermPreference {
|
||||||
|
const val ROOT_PATH = "/data/data/io.neoterm/files"
|
||||||
|
const val USR_PATH = ROOT_PATH + "/usr"
|
||||||
|
const val HOME_PATH = ROOT_PATH + "/home"
|
||||||
|
|
||||||
const val KEY_FONT_SIZE = "neoterm_general_font_size"
|
const val KEY_FONT_SIZE = "neoterm_general_font_size"
|
||||||
const val KEY_CURRENT_SESSION = "neoterm_service_current_session"
|
const val KEY_CURRENT_SESSION = "neoterm_service_current_session"
|
||||||
|
|
||||||
@ -80,4 +86,27 @@ object NeoTermPreference {
|
|||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun buildEnvironment(cwd: String?): Array<String> {
|
||||||
|
var cwd = cwd
|
||||||
|
File(HOME_PATH).mkdirs()
|
||||||
|
|
||||||
|
if (cwd == null) cwd = HOME_PATH
|
||||||
|
|
||||||
|
val termEnv = "TERM=xterm-256color"
|
||||||
|
val homeEnv = "HOME=" + 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")
|
||||||
|
|
||||||
|
val ps1Env = "PS1=$ "
|
||||||
|
val ldEnv = "LD_LIBRARY_PATH=$USR_PATH/lib"
|
||||||
|
val langEnv = "LANG=en_US.UTF-8"
|
||||||
|
val pathEnv = "PATH=$USR_PATH/bin:$USR_PATH/bin/applets"
|
||||||
|
val pwdEnv = "PWD=" + cwd
|
||||||
|
val tmpdirEnv = "TMPDIR=$USR_PATH/tmp"
|
||||||
|
|
||||||
|
return arrayOf(termEnv, homeEnv, ps1Env, ldEnv, langEnv, pathEnv, pwdEnv, androidRootEnv, androidDataEnv, externalStorageEnv, tmpdirEnv)
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,13 +10,12 @@ import android.os.Binder
|
|||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import android.support.v4.content.WakefulBroadcastReceiver
|
import android.support.v4.content.WakefulBroadcastReceiver
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
|
||||||
import java.util.ArrayList
|
|
||||||
|
|
||||||
import io.neoterm.ui.NeoTermActivity
|
|
||||||
import io.neoterm.R
|
import io.neoterm.R
|
||||||
import io.neoterm.backend.EmulatorDebug
|
import io.neoterm.backend.EmulatorDebug
|
||||||
import io.neoterm.backend.TerminalSession
|
import io.neoterm.backend.TerminalSession
|
||||||
|
import io.neoterm.preference.NeoTermPreference
|
||||||
|
import io.neoterm.ui.NeoTermActivity
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kiva
|
* @author kiva
|
||||||
@ -71,25 +70,21 @@ class NeoTermService : Service() {
|
|||||||
fun createTermSession(executablePath: String?, arguments: Array<String>?, cwd: String?, env: Array<String>?, sessionCallback: TerminalSession.SessionChangedCallback?): TerminalSession {
|
fun createTermSession(executablePath: String?, arguments: Array<String>?, cwd: String?, env: Array<String>?, sessionCallback: TerminalSession.SessionChangedCallback?): TerminalSession {
|
||||||
var executablePath = executablePath
|
var executablePath = executablePath
|
||||||
var arguments = arguments
|
var arguments = arguments
|
||||||
var cwd = cwd
|
|
||||||
if (cwd == null) cwd = filesDir.absolutePath
|
|
||||||
|
|
||||||
var isLoginShell = false
|
var cwd = cwd
|
||||||
|
if (cwd == null) {
|
||||||
|
cwd = NeoTermPreference.HOME_PATH
|
||||||
|
}
|
||||||
|
|
||||||
if (executablePath == null) {
|
if (executablePath == null) {
|
||||||
// Fall back to system shell as last resort:
|
executablePath = NeoTermPreference.USR_PATH + "/bin/bash"
|
||||||
executablePath = "/system/bin/sh"
|
|
||||||
isLoginShell = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arguments == null) {
|
if (arguments == null) {
|
||||||
arguments = arrayOf<String>(executablePath)
|
arguments = arrayOf<String>(executablePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
val lastSlashIndex = executablePath.lastIndexOf('/')
|
val session = TerminalSession(executablePath, cwd, arguments, env ?: NeoTermPreference.buildEnvironment(cwd), sessionCallback)
|
||||||
val processName = (if (isLoginShell) "-" else "") + if (lastSlashIndex == -1) executablePath else executablePath.substring(lastSlashIndex + 1)
|
|
||||||
|
|
||||||
val session = TerminalSession(executablePath, cwd, arguments, env, sessionCallback)
|
|
||||||
mTerminalSessions.add(session)
|
mTerminalSessions.add(session)
|
||||||
updateNotification()
|
updateNotification()
|
||||||
return session
|
return session
|
||||||
@ -126,9 +121,7 @@ class NeoTermService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val ACTION_SERVICE_STOP = "neoterm.action.service.stop"
|
val ACTION_SERVICE_STOP = "neoterm.action.service.stop"
|
||||||
|
|
||||||
private val NOTIFICATION_ID = 52019
|
private val NOTIFICATION_ID = 52019
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
package io.neoterm.ui
|
package io.neoterm.ui
|
||||||
|
|
||||||
|
import android.app.AlertDialog
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
|
import android.content.DialogInterface
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.ServiceConnection
|
import android.content.ServiceConnection
|
||||||
|
import android.content.pm.PackageManager
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import android.support.v4.content.ContextCompat
|
import android.support.v4.content.ContextCompat
|
||||||
@ -18,6 +21,8 @@ import de.mrapp.android.tabswitcher.*
|
|||||||
import de.mrapp.android.tabswitcher.view.TabSwitcherButton
|
import de.mrapp.android.tabswitcher.view.TabSwitcherButton
|
||||||
import io.neoterm.R
|
import io.neoterm.R
|
||||||
import io.neoterm.backend.TerminalSession
|
import io.neoterm.backend.TerminalSession
|
||||||
|
import io.neoterm.installer.BaseFileInstaller
|
||||||
|
import io.neoterm.preference.NeoPermission
|
||||||
import io.neoterm.preference.NeoTermPreference
|
import io.neoterm.preference.NeoTermPreference
|
||||||
import io.neoterm.services.NeoTermService
|
import io.neoterm.services.NeoTermService
|
||||||
import io.neoterm.ui.settings.SettingActivity
|
import io.neoterm.ui.settings.SettingActivity
|
||||||
@ -41,19 +46,23 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!termService!!.sessions.isEmpty()) {
|
BaseFileInstaller.installBaseFiles(this, {
|
||||||
for (session in termService!!.sessions) {
|
if (!termService!!.sessions.isEmpty()) {
|
||||||
addNewSession(session)
|
for (session in termService!!.sessions) {
|
||||||
|
addNewSession(session)
|
||||||
|
}
|
||||||
|
switchToSession(getStoredCurrentSessionOrLast())
|
||||||
|
} else {
|
||||||
|
tabSwitcher.showSwitcher()
|
||||||
|
addNewSession("NeoTerm #0", createRevealAnimation())
|
||||||
}
|
}
|
||||||
switchToSession(getStoredCurrentSessionOrLast())
|
})
|
||||||
} else {
|
|
||||||
tabSwitcher.showSwitcher()
|
|
||||||
addNewSession("NeoTerm #0", createRevealAnimation())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
NeoPermission.initAppPermission(this, NeoPermission.REQUEST_APP_PERMISSION)
|
||||||
NeoTermPreference.init(this)
|
NeoTermPreference.init(this)
|
||||||
if (NeoTermPreference.loadBoolean(R.string.key_ui_fullscreen, false)) {
|
if (NeoTermPreference.loadBoolean(R.string.key_ui_fullscreen, false)) {
|
||||||
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||||
@ -150,6 +159,22 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection {
|
|||||||
return super.onKeyDown(keyCode, event)
|
return super.onKeyDown(keyCode, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||||
|
when (requestCode) {
|
||||||
|
NeoPermission.REQUEST_APP_PERMISSION -> {
|
||||||
|
if (grantResults.isEmpty()
|
||||||
|
|| grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
AlertDialog.Builder(this).setMessage("应用无法取得必须的权限,正在退出")
|
||||||
|
.setPositiveButton(android.R.string.ok, { _: DialogInterface, _: Int ->
|
||||||
|
finish()
|
||||||
|
})
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun addNewSession(session: TerminalSession?) {
|
private fun addNewSession(session: TerminalSession?) {
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
return
|
return
|
||||||
@ -168,7 +193,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection {
|
|||||||
val tab = createTab(sessionName) as TermTab
|
val tab = createTab(sessionName) as TermTab
|
||||||
tab.sessionCallback = TermSessionChangedCallback()
|
tab.sessionCallback = TermSessionChangedCallback()
|
||||||
tab.viewClient = TermViewClient(this)
|
tab.viewClient = TermViewClient(this)
|
||||||
tab.termSession = termService!!.createTermSession(null, null, "/", null, tab.sessionCallback)
|
tab.termSession = termService!!.createTermSession(null, null, null, null, tab.sessionCallback)
|
||||||
|
|
||||||
if (sessionName != null) {
|
if (sessionName != null) {
|
||||||
tab.termSession!!.mSessionName = sessionName
|
tab.termSession!!.mSessionName = sessionName
|
||||||
|
Reference in New Issue
Block a user