diff --git a/README.md b/README.md index 15757fb..7085e87 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Releases on f-droid will be provided as soon as possible. ~~When there is a rele [See this comment for links to install Termux and its plugins from Github](https://github.com/tareksander/termux-gui-python-bindings/issues/1#issuecomment-983797979). [Protocol.md](Protocol.md) describes the Protocol used and the available functions you can use. -[GUIProt0.proto](app/src/main/proto/GUIProt0.proto) contains teh documentation of the newer Protobuf-based protocol with more features. +[GUIProt0.proto](app/src/main/proto/GUIProt0.proto) contains the documentation of the newer Protobuf-based protocol with more features. If you want to use overlay windows or be able to open windows from the background, go into the app settings for Termux:GUI, open the advanced section and enable "Display over other apps". ### Features diff --git a/TODO b/TODO index 3568ae1..776af44 100644 --- a/TODO +++ b/TODO @@ -8,7 +8,10 @@ Roadmap: - 1.0.0: !!! start semantic versioning from here !!! [ ] switch to the new plugin system, deprecate shared uid [ ] add more logging + [ ] Option for notifications to stay after the connection is closed + [ ] but ongoing notifications will be set to not ongoing, to allow dismissal [ ] HardwareBuffer features + [ ] render thread [ ] frame sync: signal when the Buffer is finished being written and can be used by the plugin, and signal when the plugin finished using a buffer and the client can use it again [ ] eventfd @@ -21,7 +24,7 @@ Roadmap: [ ] better framerate handling: https://developer.android.com/guide/topics/media/frame-rate [ ] C library 1.0 [ ] add error codes from protobuf to C library - [ ] add finishActivity + [x] add finishActivity [/] finish tutorial [ ] button in settings to save a logcat dump to a file [?] RelativeLayout @@ -43,21 +46,30 @@ Roadmap: [ ] more screenshots [ ] update description and readme - 1.1.0 + [ ] JSON protocol version 2 based on Protocol Buffers JSON encoding [ ] add methods for android 12 widget api [ ] settable margins and paddings [ ] better dynamic RemoteViews [ ] Stateful widgets [ ] prepopulated collections views [ ] material you theming + [ ] Quick settings tiles? + [ ] Have to be defined as services in the manifest, icon can probably be changed by a content provider or otherwise dynamically + [ ] Programs could set quick settings tiles and then listen for events on them [ ] material design components [ ] md2 [ ] md3 [ ] the material design theme should be the Activity theme + [ ] set md colors to activity colors + [ ] material you support + [ ] add a style enum to the create info message, error if a particular style isn't supported for a component. + Also allows more future versions of MD or custom styles, and can re-use the existing methods. + [ ] not for RemoteViews, these only support the plain Views [ ] update the f-droid metadata [ ] write a changelog [ ] more screenshots [ ] update description and readme - - 1.2.0: + - 2.0.0: [ ] remove shared uid [ ] additional argument to methods that require a View: subtree: id of a ViewGroup that contains the View as a child, grandchild, ... . The id gets looked up once and cached in a Hashmap (delete when view is removed). diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 23645f6..211a308 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -66,7 +66,9 @@ android:name=".GUIActivity" android:configChanges="uiMode|locale|screenSize|smallestScreenSize|screenLayout|orientation" android:exported="false" - android:supportsPictureInPicture="true" /> + android:supportsPictureInPicture="true" + android:alwaysRetainTaskState="true" + android:persistableMode="persistNever"/> , v: GUIProt0.View): OnKeyListener { + return OnKeyListener { _, _, event -> + val b = GUIProt0.KeyEvent.newBuilder() + b.v = v + b.codePoint = event.unicodeChar + var mod = 0 + if (event.isShiftPressed) mod = GUIProt0.KeyEvent.Modifier.MOD_LSHIFT_VALUE or GUIProt0.KeyEvent.Modifier.MOD_RSHIFT_VALUE + if (event.isCtrlPressed) mod = mod or GUIProt0.KeyEvent.Modifier.MOD_LCTRL_VALUE or GUIProt0.KeyEvent.Modifier.MOD_RCTRL_VALUE + if (event.isAltPressed) mod = mod or GUIProt0.KeyEvent.Modifier.MOD_ALT_VALUE + if (event.isFunctionPressed) mod = mod or GUIProt0.KeyEvent.Modifier.MOD_FN_VALUE + if (event.isCapsLockOn) mod = mod or GUIProt0.KeyEvent.Modifier.MOD_CAPS_LOCK_VALUE + if (event.isNumLockOn) mod = mod or GUIProt0.KeyEvent.Modifier.MOD_NUM_LOCK_VALUE + b.modifiers = mod + b.code = event.keyCode + eventQueue.offer(GUIProt0.Event.newBuilder().setKeyEvent(b).build()) + true + } + } + @SuppressLint("ClickableViewAccessibility") fun setTouchListenerProto(v: View, aid: Int, enabled: Boolean, eventQueue: LinkedBlockingQueue) { if (enabled) { diff --git a/app/src/main/java/com/termux/gui/protocol/protobuf/v0/HandleCreate.kt b/app/src/main/java/com/termux/gui/protocol/protobuf/v0/HandleCreate.kt index 5a20eb2..2dc7981 100644 --- a/app/src/main/java/com/termux/gui/protocol/protobuf/v0/HandleCreate.kt +++ b/app/src/main/java/com/termux/gui/protocol/protobuf/v0/HandleCreate.kt @@ -100,24 +100,17 @@ class HandleCreate(val v: V0Proto, val main: OutputStream, val activities: Mutab } } + + fun image(m: CreateImageViewRequest) { if (m.keyboard) { create.createView(m) { - it.setOnKeyListener { _, _, event -> - val b = KeyEvent.newBuilder() - b.codePoint = event.unicodeChar - var mod = 0 - if (event.isShiftPressed) mod = KeyEvent.Modifier.MOD_LSHIFT_VALUE or KeyEvent.Modifier.MOD_RSHIFT_VALUE - if (event.isCtrlPressed) mod = mod or KeyEvent.Modifier.MOD_LCTRL_VALUE or KeyEvent.Modifier.MOD_RCTRL_VALUE - if (event.isAltPressed) mod = mod or KeyEvent.Modifier.MOD_ALT_VALUE - if (event.isFunctionPressed) mod = mod or KeyEvent.Modifier.MOD_FN_VALUE - if (event.isCapsLockOn) mod = mod or KeyEvent.Modifier.MOD_CAPS_LOCK_VALUE - if (event.isNumLockOn) mod = mod or KeyEvent.Modifier.MOD_NUM_LOCK_VALUE - b.modifiers = mod - b.code = event.keyCode - eventQueue.offer(Event.newBuilder().setKeyEvent(b).build()) - true + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + it.focusable = android.view.View.FOCUSABLE + } else { + it.isFocusable = true } + it.setOnKeyListener(ProtoUtils.keyListener(eventQueue, View.newBuilder().setAid(m.data.aid).setId(it.id).build())) } } else { create.createView(m) {} @@ -287,7 +280,10 @@ class HandleCreate(val v: V0Proto, val main: OutputStream, val activities: Mutab eventQueue.offer(Event.newBuilder().setFrameComplete(SurfaceViewFrameCompleteEvent.newBuilder().setV(View.newBuilder().setAid(m.data.aid).setId(it.id)).setTimestamp(timestamp)).build()) } } - it.keyboard = m.keyboard + if (m.keyboard) { + it.focusable = android.view.View.FOCUSABLE + it.setOnKeyListener(ProtoUtils.keyListener(eventQueue, View.newBuilder().setAid(m.data.aid).setId(it.id).build())) + } it.setSecure(m.secure) } } diff --git a/app/src/main/java/com/termux/gui/protocol/protobuf/v0/HandleView.kt b/app/src/main/java/com/termux/gui/protocol/protobuf/v0/HandleView.kt index be85658..fe575ca 100644 --- a/app/src/main/java/com/termux/gui/protocol/protobuf/v0/HandleView.kt +++ b/app/src/main/java/com/termux/gui/protocol/protobuf/v0/HandleView.kt @@ -722,7 +722,6 @@ class HandleView(val v: V0Proto, val main: OutputStream, val activities: Mutable fun setSurfaceBuffer(m: SurfaceViewSetBufferRequest) { - //println("setbuffer") // setBuffer is synchronized with the rendering and so can be called from the connection thread handler.handleViewConnectionThread(m.v, SurfaceViewSetBufferResponse.newBuilder(), { ret, v: HardwareBufferSurfaceView, _, _ -> val b = hardwareBuffers[m.buffer] diff --git a/app/src/main/java/com/termux/gui/protocol/shared/v0/RawInputConnection.kt b/app/src/main/java/com/termux/gui/protocol/shared/v0/RawInputConnection.kt index 68ea2b5..4095a22 100644 --- a/app/src/main/java/com/termux/gui/protocol/shared/v0/RawInputConnection.kt +++ b/app/src/main/java/com/termux/gui/protocol/shared/v0/RawInputConnection.kt @@ -6,7 +6,7 @@ import android.view.KeyEvent import android.view.View import android.view.inputmethod.* -class RawInputConnection : InputConnection { +class RawInputConnection(private val keyListener: View.OnKeyListener) : InputConnection { override fun getTextBeforeCursor(n: Int, flags: Int): CharSequence? { return null @@ -81,7 +81,8 @@ class RawInputConnection : InputConnection { } override fun sendKeyEvent(event: KeyEvent): Boolean { - return false + keyListener.onKey(null, KeyEvent.KEYCODE_UNKNOWN, event) + return true } override fun clearMetaKeyStates(states: Int): Boolean { diff --git a/app/src/main/java/com/termux/gui/views/HardwareBufferSurfaceView.kt b/app/src/main/java/com/termux/gui/views/HardwareBufferSurfaceView.kt index 78297ef..3a84be2 100644 --- a/app/src/main/java/com/termux/gui/views/HardwareBufferSurfaceView.kt +++ b/app/src/main/java/com/termux/gui/views/HardwareBufferSurfaceView.kt @@ -125,7 +125,7 @@ class HardwareBufferSurfaceView(c: Context) : SurfaceView(c), Choreographer.Fram */ val RENDER_LOCK = Object() - var keyboard: Boolean = false + private var keyListener: OnKeyListener? = null var surfaceChangedListener: SurfaceChangedListener? = null var frameCallback: FrameCallbackListener? = null var config: Config = Config() @@ -610,15 +610,17 @@ class HardwareBufferSurfaceView(c: Context) : SurfaceView(c), Choreographer.Fram override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection { - return if (keyboard) { + val l = keyListener + return if (l != null) { outAttrs.inputType = EditorInfo.TYPE_NULL - RawInputConnection() + RawInputConnection(l) } else { super.onCreateInputConnection(outAttrs) } } override fun setOnKeyListener(l: OnKeyListener?) { + keyListener = l super.setOnKeyListener(l) } diff --git a/app/src/main/java/com/termux/gui/views/KeyboardImageView.kt b/app/src/main/java/com/termux/gui/views/KeyboardImageView.kt index b9acf5c..0f40ded 100644 --- a/app/src/main/java/com/termux/gui/views/KeyboardImageView.kt +++ b/app/src/main/java/com/termux/gui/views/KeyboardImageView.kt @@ -9,14 +9,20 @@ import com.termux.gui.protocol.shared.v0.RawInputConnection * ImageView with InputConnection to get KeyEvents. */ class KeyboardImageView(c: Context) : AppCompatImageView(c) { - - + private var keyListener: OnKeyListener? = null + override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection { - outAttrs.inputType = EditorInfo.TYPE_NULL - return RawInputConnection() + val l = keyListener + return if (l != null) { + outAttrs.inputType = EditorInfo.TYPE_NULL + RawInputConnection(l) + } else { + super.onCreateInputConnection(outAttrs) + } } - + override fun setOnKeyListener(l: OnKeyListener?) { + keyListener = l; super.setOnKeyListener(l) }