这是indexloc提供的服务,不要输入任何密码
Skip to content

Conversation

@agnostic-apollo
Copy link
Member

@agnostic-apollo agnostic-apollo commented Mar 18, 2022

UPDATE Extras changed, check d287734


This is done via addition of the com.termux.RUN_COMMAND_SESSION_CREATE_MODE extra, which currently supports two values.

  • always to always create a new session every time.
  • no-session-with-name to create a new session only if no existing session exits with the same terminal session name.

The terminal session name will equal executable basename by default and dashes - in the basename will no longer be replaced with spaces when session name as done previously. The com.termux.RUN_COMMAND_SESSION_NAME extra can be used to set custom session name.

Usage:

You can use this with Termux:Tasker or Termux:Widget.

For example for Termux:Widget

  • Create a wrapper script at ~/.shortcuts/tasks/my-script.sh with following contents under tasks directory so that it runs in background app shell instead of a terminal session. Do not use terminal session runner for wrapper script, since it will open two sessions everytime otherwise, first for wrapper script, then for actual target executable. There would also be conflicts if both wrapper script and target executable have the same basename and it would be incorrectly assumed that session is already running.
  • Replace the bash executable with actual target executable that you want to run in the terminal session if its not already running.
  • Optionally set custom session name. By default it will set to executable basename and not the wrapper script name. To set it to wrapper script name, you can pass $(basename "$0").
  • Launch the wrapper script with widget. On first launch, a new terminal session should open but on subsequent launches, same terminal session should open.

Note that you can also pass com.termux.RUN_COMMAND_SESSION_ACTION to modify session action behaviour. Check https://github.com/termux/termux-app/wiki/RUN_COMMAND-Intent#run_command-intent-command-extras.

#!/usr/bin/bash

am startservice --user 0 -n com.termux/com.termux.app.RunCommandService \
-a com.termux.RUN_COMMAND \
--es com.termux.RUN_COMMAND_PATH '/data/data/com.termux/files/usr/bin/bash' \
--es com.termux.RUN_COMMAND_SESSION_CREATE_MODE 'no-session-with-name' \
--es com.termux.RUN_COMMAND_SESSION_NAME "custom-name"

…ame` in addition to `TerminalSession.mSessionName`
…reating duplicate session for `RUN_COMMAND` intent

This is done via addition of the `com.termux.RUN_COMMAND_SESSION_CREATE_MODE` extra, which currently supports two values.

- `always` to always create a new session every time.
- `no-session-with-name` to create a new session only if no existing session exits with the same terminal session name.

The terminal session name will equal executable basename by default and dashes `-` in the basename will no longer be replaced with spaces when session name as done previously. The `com.termux.RUN_COMMAND_SESSION_NAME` extra can be used to set custom session name.

Usage:

You can use this with `Termux:Tasker` or `Termux:Widget`.

For example for `Termux:Widget`

- Create a wrapper script at `~/.shortcuts/tasks/my-script.sh` with following contents under `tasks` directory so that it runs in background app shell instead of a terminal session. Do not use terminal session runner for wrapper script, since it will open two sessions everytime otherwise, first for wrapper script, then for actual target executable. There would also be conflicts if both wrapper script and target executable have the same basename and it would be incorrectly assumed that session is already running.
- Replace the `bash` executable with actual target executable that you want to run in the terminal session if its not already running.
- Optionally set custom session name. By default it will set to executable basename and not the wrapper script name. To set it to wrapper script name, you can pass `$(basename "$0")`.
- Launch the wrapper script with widget. On first launch, a new terminal session should open but on subsequent launches, same terminal session should open.

Note that you can also pass `com.termux.RUN_COMMAND_SESSION_ACTION` to modify session action behaviour. Check https://github.com/termux/termux-app/wiki/RUN_COMMAND-Intent#run_command-intent-command-extras.

```

am startservice --user 0 -n com.termux/com.termux.app.RunCommandService \
-a com.termux.RUN_COMMAND \
--es com.termux.RUN_COMMAND_PATH '/data/data/com.termux/files/usr/bin/bash' \
--es com.termux.RUN_COMMAND_SESSION_CREATE_MODE 'no-session-with-name' \
--es com.termux.RUN_COMMAND_SESSION_NAME "custom-name"
```
@agnostic-apollo
Copy link
Member Author

agnostic-apollo commented Mar 18, 2022

Hey @trygveaa, can you test if this suits your needs. Thanks

Github actions APK link: https://github.com/termux/termux-app/actions/runs/2001675564

@agnostic-apollo
Copy link
Member Author

@trygveaa do you plan on testing this, I may need to merge this for termux-api work since that will likely result in conflicts with new/modified ResultSender implementation.

@trygveaa
Copy link
Contributor

@agnostic-apollo: Sorry! I missed your original comment. Thanks for this, I'll definitely test it asap.

@trygveaa
Copy link
Contributor

I have a potential problem with being able to test it though. I recently upgraded to Android 12 and the single shortcut widget is completely gone, the one I had disappeared, and it's missing from add widgets. I haven't had time to check out what could cause this yet.

But the widget with a list of shortcuts still exists and works, so I'll test with that.

@agnostic-apollo
Copy link
Member Author

You are welcome. Thanks for testing.

I recently upgraded to Android 12 and the single shortcut widget is completely gone,

It is showing in android 12 avd with Pixel Launcher, possible issue could be not explicitly defined exported=true for TermuxCreateShortcutActivity as per new reqs by your launcher, even though they shouldn't apply for current targetSdkVersion. Maybe try different launcher.

https://github.com/termux/termux-widget/blob/v0.13.0/app/src/main/AndroidManifest.xml#L40

https://developer.android.com/about/versions/12/behavior-changes-12#exported

@agnostic-apollo
Copy link
Member Author

And is the internal and external SessionCreateMode design fine in itself? More modes could be added in future as well if needed.

@trygveaa
Copy link
Contributor

Hm, there is a 3 second delay from pressing the widget until Termux is launched. Is it like that on your device?

@agnostic-apollo
Copy link
Member Author

It's instantaneous on my android 11 lineageOS device. You can check with termux notification, 1 task should show when TermuxService receives the intent and starts the task. Or check logcat after setting Verbose level and see if RunCommandService and TermuxService receives it at start or end of 3s.

@agnostic-apollo
Copy link
Member Author

Make sure both apps have any battery optimizations disabled.

@trygveaa
Copy link
Contributor

It is showing in android 12 avd with Pixel Launcher, possible issue could be not explicitly defined exported=true for TermuxCreateShortcutActivity as per new reqs by your launcher, even though they shouldn't apply for current targetSdkVersion. Maybe try different launcher.

https://github.com/termux/termux-widget/blob/v0.13.0/app/src/main/AndroidManifest.xml#L40

https://developer.android.com/about/versions/12/behavior-changes-12#exported

Ah, thanks for the pointer and suggestion. I tried nova launcher and it shows up there (along with others that were missing). Strangely, when I try to add it there it's added to the oneplus launcher instead. But if I change default launcher to nova it's added there. So okay, that issue is not related to Termux.

It's instantaneous on my android 11 lineageOS device. You can check with termux notification, 1 task should show when TermuxService receives the intent and starts the task. Or check logcat after setting Verbose level and see if RunCommandService and TermuxService receives it at start or end of 3s.

A notification with 1 task shows up pretty quick, but then it takes 3 seconds until the session is created or opened. As far as I can see from the log TermuxService receives the intent to start the task almost immediately, but the intent to start the actual command after 3 seconds, and RunCommandService runs after the 3 seconds. I've attached the full log: termux-widget-run-command-delay.log

Make sure both apps have any battery optimizations disabled.

Right, I tried that now, but same result unfortunately.

I'm using a OnePlus 9 Pro (LE2123) with Android 12 (LE2123_11_C.47).

And is the internal and external SessionCreateMode design fine in itself? More modes could be added in future as well if needed.

I don't know enough about the widget design to say anything about the way a widget is normally launched vs. using RUN_COMMAND, but at least when using RUN_COMMAND I think this looks good. A bit cumbersome to create though, not sure if it can be simplified? (but not that important for me, I'm fine with creating it like you described.)

@agnostic-apollo
Copy link
Member Author

agnostic-apollo commented Mar 29, 2022

Strangely, when I try to add it there it's added to the oneplus launcher instead. But if I change default launcher to nova it's added there.

Pinned shortcuts can only be launched by default launcher, so termux-widget creates it in default launcher.

but the intent to start the actual command after 3 seconds, and RunCommandService runs after the 3 seconds.

Can you try with /system/bin/am startservice

A bit cumbersome to create though, not sure if it can be simplified? (but not that important for me, I'm fine with creating it like you described.)

A library/script is planned to be provided once designs are finalized. RunCommandService will handle other APIs as well than just shell commands.

termux-widget can add direct support without needing RUN_COMMAND wrapper once .desktop files support is added.

@trygveaa
Copy link
Contributor

trygveaa commented Mar 29, 2022

Pinned shortcuts can only be launched by default launcher, so termux-widget creates it in default launcher.

Hm, it seems to work fine for other pinned shortcuts, like settings, translate and connectbot. They are added to Nova, and launch fine from Nova even though Nova is not the default launcher.

Can you try with /system/bin/am startservice

Ah, nice, that got rid of the delay. However, now my script is only launched if I run the widget when Termux is already running (just any session running, not necessarily with that session). If I try to launch the widget when Termux is not running, it just opens bash instead of my script.

A library/script is planned to be provided once designs are finalized. RunCommandService will handle other APIs as well than just shell commands.

termux-widget can add direct support without needing RUN_COMMAND wrapper once .desktop files support is added.

Perfect!

@agnostic-apollo
Copy link
Member Author

Hm, it seems to work fine for other pinned shortcuts, like settings, translate and connectbot. They are added to Nova, and launch fine from Nova even though Nova is not the default launcher.

They may be static shortcuts. termux-widget calls ShortcutManager.requestPinShortcut() and android sends pin request to currently default launcher automatically.

https://github.com/termux/termux-widget/blob/v0.13.0/app/src/main/java/com/termux/widget/TermuxCreateShortcutActivity.java#L161

https://developer.android.com/reference/android/content/pm/ShortcutManager#requestPinShortcut(android.content.pm.ShortcutInfo,%20android.content.IntentSender)

https://github.com/agnostic-apollo/TaskerLauncherShortcut#Shortcut-Types

However, now my script is only launched if I run the widget when Termux is already running (just any session running, not necessarily with that session). If I try to launch the widget when Termux is not running, it just opens bash instead of my script.

Issue is that if the initial task completes before the TermuxService starts the bash terminal session sent via RUN_COMMAND intent, then TermuxService will trigger stopSelf() on task exit because no other sessions or tasks are running. Now even if intent is delivered after that and terminal session is started, android will still call onDestroy() to stop the service and new session will be stopped. But since an intent to start the TermuxActivity would already be sent to bring session to foreground, activity starts later and creates a new default session. Just add something like sleep 5 in your script after sending RUN_COMMAND intent, which will keep the task running, giving enough time for terminal session to start before task exits, so that stopSelf() is not called. Maybe solvable with call to stopSelfResult() instead.

https://github.com/termux/termux-app/blob/v0.118.0/app/src/main/java/com/termux/app/TermuxService.java#L471

As for the delay, its because $PREFIX/bin/am provided by https://github.com/termux/TermuxAm/blob/master/am-apk-installed starts a JVM every time its called, which is slow, and affects termux-api scripts as well. The problem will be solved with termux-am-socket (#2458) which should be available in next release.

@trygveaa
Copy link
Contributor

They may be static shortcuts. termux-widget calls ShortcutManager.requestPinShortcut() and android sends pin request to currently default launcher automatically.

https://github.com/termux/termux-widget/blob/v0.13.0/app/src/main/java/com/termux/widget/TermuxCreateShortcutActivity.java#L161
https://developer.android.com/reference/android/content/pm/ShortcutManager#requestPinShortcut(android.content.pm.ShortcutInfo,%20android.content.IntentSender)

https://github.com/agnostic-apollo/TaskerLauncherShortcut#Shortcut-Types

Thanks for the pointers, I'll have to look into this in more detail when I have some time.

Issue is that if the initial task completes before the TermuxService starts the bash terminal session sent via RUN_COMMAND intent, then TermuxService will trigger stopSelf() on task exit because no other sessions or tasks are running. Now even if intent is delivered after that and terminal session is started, android will still call onDestroy() to stop the service and new session will be stopped. But since an intent to start the TermuxActivity would already be sent to bring session to foreground, activity starts later and creates a new default session. Just add something like sleep 5 in your script after sending RUN_COMMAND intent, which will keep the task running, giving enough time for terminal session to start before task exits, so that stopSelf() is not called.

Ah, makes sense. Works great with the sleep. Thanks so much for implementing this, and helping me getting it working nicely.

Maybe solvable with call to stopSelfResult() instead.

https://github.com/termux/termux-app/blob/v0.118.0/app/src/main/java/com/termux/app/TermuxService.java#L471

Seems to work with stopSelfResult too, but since that is not stopping the service since there are pending start requests, does that mean the service isn't stopped?

As for the delay, its because $PREFIX/bin/am provided by https://github.com/termux/TermuxAm/blob/master/am-apk-installed starts a JVM every time its called, which is slow, and affects termux-api scripts as well. The problem will be solved with termux-am-socket (#2458) which should be available in next release.

Does it need that am integration? Can't Termux:Widget just send the RUN_COMMAND intent directly?

@agnostic-apollo
Copy link
Member Author

You are very welcome. :)

Seems to work with stopSelfResult too, but since that is not stopping the service since there are pending start requests, does that mean the service isn't stopped?

Yup. It's not gonna be that simple. Will need to implement synchronization logic to handle that and will be time consuming. I have added it to my todo list, will do it at some point. It's not a bug with the current feature add anyways and is an old bug from before my time and initial commit.

https://stackoverflow.com/questions/21081100/android-service-stopselfint

I handled a similar case before as well.

https://github.com/termux/termux-app/blob/v0.118.0/app/src/main/java/com/termux/app/TermuxService.java#L232

Does it need that am integration? Can't Termux:Widget just send the RUN_COMMAND intent directly?

No it does not. Termux:Widget directly sends intents to TermuxService and can use its extras and doesn't go through RunCommandService. RUN_COMMAND acts as a public API, the TermuxService is for private termux apps usage. However, it can't be done until .desktop files is implemented for user to actually set session create mode for a shortcut file.

/** Intent {@code String} extra for session name for {@link Runner#TERMINAL_SESSION} commands for the TERMUX_SERVICE.ACTION_SERVICE_EXECUTE intent */

Since feature is working fine, I will merge this unless there are any objections.

@trygveaa
Copy link
Contributor

Yup. It's not gonna be that simple. Will need to implement synchronization logic to handle that and will be time consuming. I have added it to my todo list, will do it at some point. It's not a bug with the current feature add anyways and is an old bug from before my time and initial commit.

Right, not a big problem anyways (at least for my use case).

No it does not. Termux:Widget directly sends intents to TermuxService and can use its extras and doesn't go through RunCommandService. RUN_COMMAND acts as a public API, the TermuxService is for private termux apps usage. However, it can't be done until .desktop files is implemented for user to actually set session create mode for a shortcut file.

Great!

Since feature is working fine, I will merge this unless there are any objections.

Yes, please do :)

@agnostic-apollo agnostic-apollo merged commit 136379d into master Apr 7, 2022
@agnostic-apollo agnostic-apollo deleted the switch-to-session branch April 7, 2022 21:47
@agnostic-apollo
Copy link
Member Author

Yes, please do :)

Great. Done! :)

@agnostic-apollo
Copy link
Member Author

@trygveaa you may wanna test #2458 (comment) too if you want, for your am delay issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants