Feature: Add X sessions

This commit is contained in:
zt515 2017-11-24 00:59:03 +08:00
parent 2033accbee
commit 6158752b8e
11 changed files with 165 additions and 34 deletions

View File

@ -0,0 +1,8 @@
package io.neoterm.frontend.xorg;
/**
* @author kiva
*/
public class XParameter {
}

View File

@ -1,11 +1,18 @@
package io.neoterm.frontend.xorg
import android.content.Context
import io.neoterm.backend.TerminalSession
/**
* @author kiva
*/
class XSession {
class XSession private constructor() {
companion object {
fun createSession(context: Context, parameter: XParameter) : XSession {
return XSession()
}
}
var mSessionName = "";
}

View File

@ -10,14 +10,14 @@ import android.os.Build
import android.os.IBinder
import android.os.PowerManager
import android.support.v4.app.NotificationCompat
import android.support.v4.content.WakefulBroadcastReceiver
import io.neoterm.R
import io.neoterm.backend.EmulatorDebug
import io.neoterm.backend.TerminalSession
import io.neoterm.frontend.shell.ShellParameter
import io.neoterm.frontend.xorg.XParameter
import io.neoterm.frontend.xorg.XSession
import io.neoterm.ui.term.NeoTermActivity
import io.neoterm.utils.TerminalUtils
import java.util.*
/**
@ -31,6 +31,7 @@ class NeoTermService : Service() {
private val serviceBinder = NeoTermBinder()
private val mTerminalSessions = ArrayList<TerminalSession>()
private val mXSessions = ArrayList<XSession>()
private var mWakeLock: PowerManager.WakeLock? = null
private var mWifiLock: WifiManager.WifiLock? = null
@ -58,11 +59,6 @@ class NeoTermService : Service() {
ACTION_RELEASE_LOCK -> releaseLock()
}
if (flags and Service.START_FLAG_REDELIVERY == 0) {
// Service is started by WBR, not restarted by system, so release the WakeLock from WBR.
WakefulBroadcastReceiver.completeWakefulIntent(intent)
}
return Service.START_NOT_STICKY
}
@ -77,6 +73,9 @@ class NeoTermService : Service() {
val sessions: List<TerminalSession>
get() = mTerminalSessions
val xSessions: List<XSession>
get() = mXSessions
fun createTermSession(parameter: ShellParameter): TerminalSession {
val session = TerminalUtils.createShellSession(this, parameter)
mTerminalSessions.add(session)
@ -93,6 +92,22 @@ class NeoTermService : Service() {
return indexOfRemoved
}
fun createXSession(parameter: XParameter): XSession {
val session = XSession.createSession(this, parameter)
mXSessions.add(session)
updateNotification()
return session
}
fun removeXSession(sessionToRemove: XSession): Int {
val indexOfRemoved = mXSessions.indexOf(sessionToRemove)
if (indexOfRemoved >= 0) {
mXSessions.removeAt(indexOfRemoved)
updateNotification()
}
return indexOfRemoved
}
private fun updateNotification() {
val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
service.notify(NOTIFICATION_ID, createNotification())
@ -104,7 +119,8 @@ class NeoTermService : Service() {
val pendingIntent = PendingIntent.getActivity(this, 0, notifyIntent, 0)
val sessionCount = mTerminalSessions.size
var contentText = getString(R.string.service_status_text, sessionCount)
val xSessionCount = mXSessions.size
var contentText = getString(R.string.service_status_text, sessionCount, xSessionCount)
val lockAcquired = mWakeLock != null
if (lockAcquired) contentText += getString(R.string.service_lock_acquired)

View File

@ -24,15 +24,18 @@ import io.neoterm.component.setup.BaseFileInstaller
import io.neoterm.frontend.client.TermSessionCallback
import io.neoterm.frontend.client.TermViewClient
import io.neoterm.frontend.client.event.*
import io.neoterm.frontend.logging.NLog
import io.neoterm.frontend.preference.NeoPermission
import io.neoterm.frontend.preference.NeoPreference
import io.neoterm.frontend.shell.ShellParameter
import io.neoterm.frontend.xorg.XParameter
import io.neoterm.frontend.xorg.XSession
import io.neoterm.services.NeoTermService
import io.neoterm.ui.pm.PackageManagerActivity
import io.neoterm.ui.settings.SettingActivity
import io.neoterm.ui.setup.SetupActivity
import io.neoterm.ui.term.tab.NeoTabDecorator
import io.neoterm.ui.term.tab.TermTab
import io.neoterm.ui.term.tab.TermTabDecorator
import io.neoterm.ui.term.tab.XSessionTab
import io.neoterm.utils.FullScreenHelper
import io.neoterm.utils.RangedInt
@ -82,7 +85,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
})
tabSwitcher = findViewById(R.id.tab_switcher)
tabSwitcher.decorator = TermTabDecorator(this)
tabSwitcher.decorator = NeoTabDecorator(this)
ViewCompat.setOnApplyWindowInsetsListener(tabSwitcher, createWindowInsetsListener())
tabSwitcher.showToolbars(false)
@ -193,7 +196,9 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
override fun onTabRemoved(tabSwitcher: TabSwitcher, index: Int, tab: Tab, animation: Animation) {
if (tab is TermTab) {
closeTab(tab)
SessionRemover.removeSession(termService, tab)
} else if (tab is XSessionTab) {
SessionRemover.removeXSession(termService, tab)
}
}
@ -349,6 +354,10 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
addNewSession(session)
}
for (session in termService!!.xSessions) {
addXSession(session)
}
if (intent?.action == Intent.ACTION_RUN) {
// app shortcuts
addNewSession(null,
@ -446,13 +455,49 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
}
private fun addXSession() {
if (!tabSwitcher.isSwitcherShown) {
toggleSwitcher(showSwitcher = true, easterEgg = false)
}
// TODO: Start X server
val parameter = XParameter()
val session = termService!!.createXSession(parameter)
session.mSessionName = generateXSessionName("X")
val tab = createXTab(session.mSessionName) as XSessionTab
tab.session = session
addNewTab(tab, createRevealAnimation())
switchToSession(tab)
}
private fun addXSession(session: XSession?) {
if (session == null) {
return
}
// Do not add the same session again
// Or app will crash when rotate
val tabCount = tabSwitcher.count
(0..(tabCount - 1))
.map { tabSwitcher.getTab(it) }
.filter { it is XSessionTab && it.session == session }
.forEach { return }
val tab = createXTab(session.mSessionName) as XSessionTab
addNewTab(tab, createRevealAnimation())
switchToSession(tab)
}
private fun generateSessionName(prefix: String): String {
return "$prefix #${termService!!.sessions.size}"
}
private fun generateXSessionName(prefix: String): String {
return "$prefix #${termService!!.xSessions.size}"
}
private fun switchToSession(session: TerminalSession?) {
if (session == null) {
return
@ -500,7 +545,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
return postTabCreated(XSessionTab(tabTitle ?: "NeoTerm"))
}
private fun <T : Tab> postTabCreated(tab: T) : T {
private fun <T : Tab> postTabCreated(tab: T): T {
// We must create a Bundle for each tab
// tabs can use them to store status.
tab.parameters = Bundle()
@ -554,10 +599,6 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
}
}
private fun closeTab(tab: TermTab) {
SessionRemover.removeSession(termService, tab)
}
private fun toggleSwitcher(showSwitcher: Boolean, easterEgg: Boolean) {
if (tabSwitcher.count == 0 && easterEgg) {
App.get().easterEgg(this, "Stop! You don't know what you are doing!")

View File

@ -1,8 +1,11 @@
package io.neoterm.ui.term
import io.neoterm.backend.TerminalSession
import io.neoterm.frontend.logging.NLog
import io.neoterm.frontend.xorg.XSession
import io.neoterm.services.NeoTermService
import io.neoterm.ui.term.tab.TermTab
import io.neoterm.ui.term.tab.XSessionTab
/**
* @author kiva
@ -14,6 +17,10 @@ object SessionRemover {
tab.cleanup()
}
fun removeXSession(termService: NeoTermService?, tab: XSessionTab?) {
removeFinishedSession(termService, tab?.session)
}
private fun removeFinishedSession(termService: NeoTermService?, finishedSession: TerminalSession?) {
if (termService == null || finishedSession == null) {
return
@ -21,4 +28,12 @@ object SessionRemover {
termService.removeTermSession(finishedSession)
}
}
private fun removeFinishedSession(termService: NeoTermService?, finishedSession: XSession?) {
if (termService == null || finishedSession == null) {
return
}
termService.removeXSession(finishedSession)
}
}

View File

@ -22,25 +22,51 @@ import io.neoterm.utils.TerminalUtils
/**
* @author kiva
*/
class TermTabDecorator(val context: NeoTermActivity) : TabSwitcherDecorator() {
class NeoTabDecorator(val context: NeoTermActivity) : TabSwitcherDecorator() {
companion object {
private val VIEW_TYPE_TERM = 1
private val VIEW_TYPE_X = 2
}
override fun onInflateView(inflater: LayoutInflater, parent: ViewGroup?, viewType: Int): View {
val view = inflater.inflate(R.layout.ui_term, parent, false)
return view
return when (viewType) {
VIEW_TYPE_TERM -> {
inflater.inflate(R.layout.ui_term, parent, false)
}
VIEW_TYPE_X -> {
inflater.inflate(R.layout.ui_xorg, parent, false)
}
else -> {
throw RuntimeException("Unknown view type")
}
}
}
override fun onShowTab(context: Context, tabSwitcher: TabSwitcher,
view: View, tab: Tab, index: Int, viewType: Int, savedInstanceState: Bundle?) {
val toolbar = this@TermTabDecorator.context.toolbar
val toolbar = this@NeoTabDecorator.context.toolbar
toolbar.title = if (tabSwitcher.isSwitcherShown) null else tab.title
if (tab is TermTab) {
tab.toolbar = toolbar
}
when (viewType) {
VIEW_TYPE_TERM -> {
val termTab = tab as TermTab
termTab.toolbar = toolbar
val terminalView = findViewById<TerminalView>(R.id.terminal_view)
val extraKeysView = findViewById<ExtraKeysView>(R.id.extra_keys)
bindTerminalView(termTab, terminalView, extraKeysView)
terminalView.requestFocus()
}
val terminalView = findViewById<TerminalView>(R.id.terminal_view)
val extraKeysView = findViewById<ExtraKeysView>(R.id.extra_keys)
bindTerminalView(tab, terminalView, extraKeysView)
terminalView.requestFocus()
VIEW_TYPE_X -> {
val xtab = tab as XSessionTab
bindXSessionView(tab)
}
}
}
private fun bindXSessionView(tab: XSessionTab) {
}
private fun bindTerminalView(tab: Tab, view: TerminalView?, extraKeysView: ExtraKeysView?) {
@ -84,10 +110,15 @@ class TermTabDecorator(val context: NeoTermActivity) : TabSwitcherDecorator() {
}
override fun getViewTypeCount(): Int {
return 1
return 2
}
override fun getViewType(tab: Tab, index: Int): Int {
if (tab is TermTab) {
return VIEW_TYPE_TERM
} else if (tab is XSessionTab) {
return VIEW_TYPE_X
}
return 0
}
}

View File

@ -1,10 +1,11 @@
package io.neoterm.ui.term.tab
import de.mrapp.android.tabswitcher.Tab
import io.neoterm.frontend.xorg.XSession
/**
* @author kiva
*/
class XSessionTab(title: CharSequence) : Tab(title) {
var session: XSession? = null
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello X Server! Comming soon."/>
</RelativeLayout>

View File

@ -75,7 +75,7 @@
<string name="crash_app">应用: %s</string>
<string name="crash_stack_trace">堆栈信息</string>
<string name="crash_tips">我们正努力让这个 Activity 永不见天日…</string>
<string name="service_status_text">%d 个会话</string>
<string name="service_status_text">%d 个会话, %d 个图形会话</string>
<string name="service_lock_acquired"> (永不休眠)</string>
<string name="service_acquire_lock">取得休眠锁</string>
<string name="service_release_lock">释放休眠锁</string>

View File

@ -70,7 +70,7 @@
<string name="crash_app">程式: %s</string>
<string name="crash_stack_trace">錯誤訊息</string>
<string name="crash_tips">我們正在努力讓這個 Activity 永不見天日…</string>
<string name="service_status_text">%d 個會話</string>
<string name="service_status_text">%d 個會話, %d 個图形會話</string>
<string name="service_lock_acquired"> (永不休眠)</string>
<string name="service_acquire_lock">開啟休眠鎖</string>
<string name="service_release_lock">關閉休眠鎖</string>

View File

@ -7,7 +7,7 @@
<string name="toggle_tab_switcher_menu_item">Toggle Tabs</string>
<string name="new_session">New Session</string>
<string name="new_system_session">New System Shell</string>
<string name="service_status_text">%d session(s)</string>
<string name="service_status_text">%d session(s), %d X session(s)</string>
<string name="service_lock_acquired"> (Wake Locked)</string>
<string name="service_acquire_lock">Acquire Lock</string>
<string name="service_release_lock">Release Lock</string>