Feature: Now we can use system shell if base fail installation failed
This commit is contained in:
@ -1,15 +1,11 @@
|
|||||||
package io.neoterm.installer;
|
package io.neoterm.installer;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.DialogInterface.OnClickListener;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.view.WindowManager;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -27,11 +23,14 @@ import io.neoterm.backend.EmulatorDebug;
|
|||||||
import io.neoterm.preference.NeoTermPreference;
|
import io.neoterm.preference.NeoTermPreference;
|
||||||
|
|
||||||
public final class BaseFileInstaller {
|
public final class BaseFileInstaller {
|
||||||
|
public static interface ResultListener {
|
||||||
|
void onResult(Exception error);
|
||||||
|
}
|
||||||
|
|
||||||
public static void installBaseFiles(final Activity activity, final Runnable whenDone) {
|
public static void installBaseFiles(final Activity activity, final ResultListener resultListener) {
|
||||||
final File PREFIX_FILE = new File(NeoTermPreference.USR_PATH);
|
final File PREFIX_FILE = new File(NeoTermPreference.USR_PATH);
|
||||||
if (PREFIX_FILE.isDirectory()) {
|
if (PREFIX_FILE.isDirectory()) {
|
||||||
whenDone.run();
|
resultListener.onResult(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +101,7 @@ public final class BaseFileInstaller {
|
|||||||
activity.runOnUiThread(new Runnable() {
|
activity.runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
whenDone.run();
|
resultListener.onResult(null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
@ -111,21 +110,8 @@ public final class BaseFileInstaller {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
new AlertDialog.Builder(activity).setTitle("ERROR").setMessage(e.toString())
|
resultListener.onResult(e);
|
||||||
.setNegativeButton("Abort", new OnClickListener() {
|
} catch (RuntimeException e) {
|
||||||
@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.
|
// Activity already dismissed - ignore.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,7 +137,7 @@ public final class BaseFileInstaller {
|
|||||||
return new URL("https://kernel19.cc/neoterm/boot/" + archName + ".zip");
|
return new URL("https://kernel19.cc/neoterm/boot/" + archName + ".zip");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String determineArchName() {
|
public static String determineArchName() {
|
||||||
for (String androidArch : Build.SUPPORTED_ABIS) {
|
for (String androidArch : Build.SUPPORTED_ABIS) {
|
||||||
switch (androidArch) {
|
switch (androidArch) {
|
||||||
case "arm64-v8a":
|
case "arm64-v8a":
|
||||||
|
@ -87,7 +87,7 @@ object NeoTermPreference {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun buildEnvironment(cwd: String?): Array<String> {
|
fun buildEnvironment(cwd: String?, systemShell: Boolean): Array<String> {
|
||||||
var cwd = cwd
|
var cwd = cwd
|
||||||
File(HOME_PATH).mkdirs()
|
File(HOME_PATH).mkdirs()
|
||||||
|
|
||||||
@ -99,6 +99,11 @@ object NeoTermPreference {
|
|||||||
val androidDataEnv = "ANDROID_DATA=" + System.getenv("ANDROID_DATA")
|
val androidDataEnv = "ANDROID_DATA=" + System.getenv("ANDROID_DATA")
|
||||||
val externalStorageEnv = "EXTERNAL_STORAGE=" + System.getenv("EXTERNAL_STORAGE")
|
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 ps1Env = "PS1=$ "
|
||||||
val ldEnv = "LD_LIBRARY_PATH=$USR_PATH/lib"
|
val ldEnv = "LD_LIBRARY_PATH=$USR_PATH/lib"
|
||||||
val langEnv = "LANG=en_US.UTF-8"
|
val langEnv = "LANG=en_US.UTF-8"
|
||||||
@ -107,6 +112,6 @@ object NeoTermPreference {
|
|||||||
val tmpdirEnv = "TMPDIR=$USR_PATH/tmp"
|
val tmpdirEnv = "TMPDIR=$USR_PATH/tmp"
|
||||||
|
|
||||||
return arrayOf(termEnv, homeEnv, ps1Env, ldEnv, langEnv, pathEnv, pwdEnv, androidRootEnv, androidDataEnv, externalStorageEnv, tmpdirEnv)
|
return arrayOf(termEnv, homeEnv, ps1Env, ldEnv, langEnv, pathEnv, pwdEnv, androidRootEnv, androidDataEnv, externalStorageEnv, tmpdirEnv)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ class NeoTermService : Service() {
|
|||||||
val sessions: List<TerminalSession>
|
val sessions: List<TerminalSession>
|
||||||
get() = mTerminalSessions
|
get() = mTerminalSessions
|
||||||
|
|
||||||
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?, systemShell: Boolean): TerminalSession {
|
||||||
var executablePath = executablePath
|
var executablePath = executablePath
|
||||||
var arguments = arguments
|
var arguments = arguments
|
||||||
|
|
||||||
@ -77,14 +77,14 @@ class NeoTermService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (executablePath == null) {
|
if (executablePath == null) {
|
||||||
executablePath = NeoTermPreference.USR_PATH + "/bin/bash"
|
executablePath = if (systemShell) "/system/bin/sh" else NeoTermPreference.USR_PATH + "/bin/sh"
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arguments == null) {
|
if (arguments == null) {
|
||||||
arguments = arrayOf<String>(executablePath)
|
arguments = arrayOf<String>(executablePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
val session = TerminalSession(executablePath, cwd, arguments, env ?: NeoTermPreference.buildEnvironment(cwd), sessionCallback)
|
val session = TerminalSession(executablePath, cwd, arguments, env ?: NeoTermPreference.buildEnvironment(cwd, systemShell), sessionCallback)
|
||||||
mTerminalSessions.add(session)
|
mTerminalSessions.add(session)
|
||||||
updateNotification()
|
updateNotification()
|
||||||
return session
|
return session
|
||||||
|
@ -31,6 +31,7 @@ import io.neoterm.view.tab.*
|
|||||||
|
|
||||||
class NeoTermActivity : AppCompatActivity(), ServiceConnection {
|
class NeoTermActivity : AppCompatActivity(), ServiceConnection {
|
||||||
lateinit var tabSwitcher: TabSwitcher
|
lateinit var tabSwitcher: TabSwitcher
|
||||||
|
var systemShell = true
|
||||||
var termService: NeoTermService? = null
|
var termService: NeoTermService? = null
|
||||||
|
|
||||||
override fun onServiceDisconnected(name: ComponentName?) {
|
override fun onServiceDisconnected(name: ComponentName?) {
|
||||||
@ -46,7 +47,10 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseFileInstaller.installBaseFiles(this, {
|
var resultListener: BaseFileInstaller.ResultListener? = null
|
||||||
|
resultListener = BaseFileInstaller.ResultListener { error ->
|
||||||
|
if (error == null) {
|
||||||
|
systemShell = false
|
||||||
if (!termService!!.sessions.isEmpty()) {
|
if (!termService!!.sessions.isEmpty()) {
|
||||||
for (session in termService!!.sessions) {
|
for (session in termService!!.sessions) {
|
||||||
addNewSession(session)
|
addNewSession(session)
|
||||||
@ -54,9 +58,24 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection {
|
|||||||
switchToSession(getStoredCurrentSessionOrLast())
|
switchToSession(getStoredCurrentSessionOrLast())
|
||||||
} else {
|
} else {
|
||||||
tabSwitcher.showSwitcher()
|
tabSwitcher.showSwitcher()
|
||||||
addNewSession("NeoTerm #0", createRevealAnimation())
|
addNewSession("NeoTerm #0", systemShell, createRevealAnimation())
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
AlertDialog.Builder(this@NeoTermActivity)
|
||||||
|
.setTitle("Error")
|
||||||
|
.setMessage(error.toString())
|
||||||
|
.setNegativeButton("System Shell", { _, _ ->
|
||||||
|
tabSwitcher.showSwitcher()
|
||||||
|
addNewSession("NeoTerm #0", systemShell, createRevealAnimation())
|
||||||
})
|
})
|
||||||
|
.setPositiveButton("Retry", { dialog, _ ->
|
||||||
|
dialog.dismiss()
|
||||||
|
BaseFileInstaller.installBaseFiles(this@NeoTermActivity, resultListener)
|
||||||
|
}).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseFileInstaller.installBaseFiles(this, resultListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@ -189,11 +208,11 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection {
|
|||||||
switchToSession(tab)
|
switchToSession(tab)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addNewSession(sessionName: String?, animation: Animation) {
|
private fun addNewSession(sessionName: String?, systemShell: Boolean, animation: Animation) {
|
||||||
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, null, tab.sessionCallback)
|
tab.termSession = termService!!.createTermSession(null, null, null, null, tab.sessionCallback, systemShell)
|
||||||
|
|
||||||
if (sessionName != null) {
|
if (sessionName != null) {
|
||||||
tab.termSession!!.mSessionName = sessionName
|
tab.termSession!!.mSessionName = sessionName
|
||||||
@ -255,7 +274,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection {
|
|||||||
fun createAddSessionListener(): View.OnClickListener {
|
fun createAddSessionListener(): View.OnClickListener {
|
||||||
return View.OnClickListener {
|
return View.OnClickListener {
|
||||||
val index = tabSwitcher.count
|
val index = tabSwitcher.count
|
||||||
addNewSession("NeoTerm #" + index, createRevealAnimation())
|
addNewSession("NeoTerm #" + index, systemShell, createRevealAnimation())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,7 +290,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection {
|
|||||||
tabSwitcher.showSwitcher()
|
tabSwitcher.showSwitcher()
|
||||||
}
|
}
|
||||||
val index = tabSwitcher.count
|
val index = tabSwitcher.count
|
||||||
addNewSession("NeoTerm #" + index, createRevealAnimation())
|
addNewSession("NeoTerm #" + index, systemShell, createRevealAnimation())
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
else -> false
|
else -> false
|
||||||
@ -283,16 +302,18 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection {
|
|||||||
val tab = TermTab(tabTitle ?: "NeoTerm")
|
val tab = TermTab(tabTitle ?: "NeoTerm")
|
||||||
tab.closeTabProvider = object : CloseTabProvider {
|
tab.closeTabProvider = object : CloseTabProvider {
|
||||||
override fun closeTab(tab: Tab) {
|
override fun closeTab(tab: Tab) {
|
||||||
// FIXME: No Such Tab
|
|
||||||
tabSwitcher.showSwitcher()
|
tabSwitcher.showSwitcher()
|
||||||
tabSwitcher.removeTab(tab)
|
tabSwitcher.removeTab(tab)
|
||||||
|
|
||||||
if (tabSwitcher.count > 1) {
|
if (tabSwitcher.count > 1) {
|
||||||
var index = tabSwitcher.indexOf(tab)
|
var index = tabSwitcher.indexOf(tab)
|
||||||
|
if (NeoTermPreference.loadBoolean(R.string.key_ui_next_tab_anim, false)) {
|
||||||
|
// 关闭当前窗口后,向下一个窗口切换
|
||||||
|
if (--index < 0) index = tabSwitcher.count - 1
|
||||||
|
} else {
|
||||||
// 关闭当前窗口后,向上一个窗口切换
|
// 关闭当前窗口后,向上一个窗口切换
|
||||||
if (++index >= tabSwitcher.count) index = 0
|
if (++index >= tabSwitcher.count) index = 0
|
||||||
// 关闭当前窗口后,向下一个窗口切换
|
}
|
||||||
// if (--index < 0) index = tabSwitcher.count - 1
|
|
||||||
switchToSession(tabSwitcher.getTab(index))
|
switchToSession(tabSwitcher.getTab(index))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -319,9 +340,9 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection {
|
|||||||
return RevealAnimation.Builder().setX(x).setY(y).create()
|
return RevealAnimation.Builder().setX(x).setY(y).create()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createPeekAnimation(): Animation {
|
// private fun createPeekAnimation(): Animation {
|
||||||
return PeekAnimation.Builder().setX(tabSwitcher.width / 2f).create()
|
// return PeekAnimation.Builder().setX(tabSwitcher.width / 2f).create()
|
||||||
}
|
// }
|
||||||
|
|
||||||
private fun getNavigationMenuItem(): View? {
|
private fun getNavigationMenuItem(): View? {
|
||||||
val toolbars = tabSwitcher.toolbars
|
val toolbars = tabSwitcher.toolbars
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
<string name="key_ui_fullscreen" translatable="false">neoterm_ui_fullscreen</string>
|
<string name="key_ui_fullscreen" translatable="false">neoterm_ui_fullscreen</string>
|
||||||
<string name="key_ui_font" translatable="false">neoterm_ui_font</string>
|
<string name="key_ui_font" translatable="false">neoterm_ui_font</string>
|
||||||
<string name="key_ui_color_scheme" translatable="false">neoterm_ui_color_scheme</string>
|
<string name="key_ui_color_scheme" translatable="false">neoterm_ui_color_scheme</string>
|
||||||
|
<string name="key_ui_next_tab_anim" translatable="false">neoterm_ui_next_tab_anim</string>
|
||||||
|
|
||||||
<string name="key_package_source" translatable="false">neoterm_package_source</string>
|
<string name="key_package_source" translatable="false">neoterm_package_source</string>
|
||||||
</resources>
|
</resources>
|
@ -24,5 +24,12 @@
|
|||||||
<string name="pref_ui_fullscreen">Full Screen</string>
|
<string name="pref_ui_fullscreen">Full Screen</string>
|
||||||
<string name="pref_ui_font">Font</string>
|
<string name="pref_ui_font">Font</string>
|
||||||
<string name="pref_ui_color_scheme">Color Scheme</string>
|
<string name="pref_ui_color_scheme">Color Scheme</string>
|
||||||
|
<string name="pref_ui_close_tab_anim_next_tab">Next tab animation</string>
|
||||||
|
<string name="pref_ui_close_tab_anim_next_tab_desc">Switch to next tab instead of previous tab when closing tab</string>
|
||||||
<string name="pref_package_source">Source</string>
|
<string name="pref_package_source">Source</string>
|
||||||
|
|
||||||
|
<string-array name="pref_ui_color_scheme_entries">
|
||||||
|
<item>Default</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<EditTextPreference
|
<EditTextPreference
|
||||||
|
android:enabled="false"
|
||||||
android:key="@string/key_package_source"
|
android:key="@string/key_package_source"
|
||||||
android:title="@string/pref_package_source" />
|
android:title="@string/pref_package_source" />
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
@ -6,13 +6,20 @@
|
|||||||
android:key="@string/key_ui_fullscreen"
|
android:key="@string/key_ui_fullscreen"
|
||||||
android:title="@string/pref_ui_fullscreen" />
|
android:title="@string/pref_ui_fullscreen" />
|
||||||
|
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="@string/key_ui_next_tab_anim"
|
||||||
|
android:summary="@string/pref_ui_close_tab_anim_next_tab_desc"
|
||||||
|
android:title="@string/pref_ui_close_tab_anim_next_tab" />
|
||||||
|
|
||||||
<EditTextPreference
|
<EditTextPreference
|
||||||
android:key="@string/key_ui_font"
|
android:key="@string/key_ui_font"
|
||||||
android:title="@string/pref_ui_font" />
|
android:title="@string/pref_ui_font" />
|
||||||
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:entries="@null"
|
android:defaultValue="Default"
|
||||||
android:entryValues="@null"
|
android:entries="@array/pref_ui_color_scheme_entries"
|
||||||
|
android:entryValues="@array/pref_ui_color_scheme_entries"
|
||||||
android:key="@string/key_ui_color_scheme"
|
android:key="@string/key_ui_color_scheme"
|
||||||
android:title="@string/pref_ui_color_scheme" />
|
android:title="@string/pref_ui_color_scheme" />
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
Reference in New Issue
Block a user