'Receive result from Termux through RUN_COMMAND_SERVICE intent
I have developped an android app to send an intent to Termux and have it run a specific task. I have managed to do so, with the following code:
public void downloadWithReponse() {
Intent intent = new Intent();
intent.setClassName("com.termux", "com.termux.app.RunCommandService");
intent.setAction("com.termux.RUN_COMMAND");
intent.putExtra("com.termux.RUN_COMMAND_PATH", "/data/data/com.termux/files/usr/bin/touch");
intent.putExtra("com.termux.RUN_COMMAND_ARGUMENTS", new String[]{"/sdcard/test.txt"});
intent.putExtra("com.termux.RUN_COMMAND_BACKGROUND", true);
intent.putExtra(TermuxConstants.TERMUX_APP.RUN_COMMAND_SERVICE.EXTRA_SESSION_ACTION, "0");
intent.putExtra(TermuxConstants.TERMUX_APP.RUN_COMMAND_SERVICE.EXTRA_COMMAND_LABEL, "touch command");
intent.putExtra(TermuxConstants.TERMUX_APP.RUN_COMMAND_SERVICE.EXTRA_COMMAND_DESCRIPTION, "Runs the touch command to show processes using the most resources.");
// Create the intent for the IntentService class that should be sent the result by TermuxService
Intent pluginResultsServiceIntent = new Intent(MainActivity.this, PluginResultsService.class);
// Generate a unique execution id for this execution command
int executionId = PluginResultsService.getNextExecutionId();
// Optional put an extra that uniquely identifies the command internally for your app.
// This can be an Intent extra as well with more extras instead of just an int.
pluginResultsServiceIntent.putExtra(PluginResultsService.EXTRA_EXECUTION_ID, executionId);
// Create the PendingIntent that will be used by TermuxService to send result of
// commands back to the IntentService
// Note that the requestCode (currently executionId) must be unique for each pending
// intent, even if extras are different, otherwise only the result of only the first
// execution will be returned since pending intent will be cancelled by android
// after the first result has been sent back via the pending intent and termux
// will not be able to send more.
PendingIntent pendingIntent = PendingIntent.getService(MainActivity.this, executionId, pluginResultsServiceIntent, PendingIntent.FLAG_ONE_SHOT);
intent.putExtra(TermuxConstants.TERMUX_APP.RUN_COMMAND_SERVICE.EXTRA_PENDING_INTENT, pendingIntent);
try {
// Send command intent for execution
Log.d("Termux", "Sending execution command with id " + executionId);
//startService(intent);
startForegroundService(intent);
} catch (Exception e) {
Log.e("Termux", "Failed to start execution command with id " + executionId + ": " + e.getMessage());
}
}
With the class PluginResultsService:
public class PluginResultsService extends IntentService {
public static final String EXTRA_EXECUTION_ID = "execution_id";
private static int EXECUTION_ID = 1000;
public static final String PLUGIN_SERVICE_LABEL = "PluginResultsService";
private static final String LOG_TAG = "PluginResultsService";
public PluginResultsService(){
super(PLUGIN_SERVICE_LABEL);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
if (intent == null) return;
Log.d(LOG_TAG, PLUGIN_SERVICE_LABEL + " received execution result");
final Bundle resultBundle = intent.getBundleExtra(TermuxConstants.TERMUX_APP.TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE);
if (resultBundle == null) {
Log.e(LOG_TAG, "The intent does not contain the result bundle at the \"" + TermuxConstants.TERMUX_APP.TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE + "\" key.");
return;
}
final int executionId = intent.getIntExtra(EXTRA_EXECUTION_ID, 0);
Log.d(LOG_TAG, "Execution id " + executionId + " result:\n" +
"stdout:\n```\n" + resultBundle.getString(TermuxConstants.TERMUX_APP.TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT, "") + "\n```\n" +
"stdout_original_length: `" + resultBundle.getString(TermuxConstants.TERMUX_APP.TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT_ORIGINAL_LENGTH) + "`\n" +
"stderr:\n```\n" + resultBundle.getString(TermuxConstants.TERMUX_APP.TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_STDERR, "") + "\n```\n" +
"stderr_original_length: `" + resultBundle.getString(TermuxConstants.TERMUX_APP.TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_STDERR_ORIGINAL_LENGTH) + "`\n" +
"exitCode: `" + resultBundle.getInt(TermuxConstants.TERMUX_APP.TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE) + "`\n" +
"errCode: `" + resultBundle.getInt(TermuxConstants.TERMUX_APP.TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_ERR) + "`\n" +
"errmsg: `" + resultBundle.getString(TermuxConstants.TERMUX_APP.TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_ERRMSG, "") + "`");
}
public static synchronized int getNextExecutionId() {
return EXECUTION_ID++;
}
}
The code above runs fine. I can see the file created in the sdcard directory, and I can see the logs in adb with logcat.
My problem is I can't seem to find a way to get a response from Termux in my Android app, to see if the command is executed, or if failed, etc. I have tried reading the logcat from my app, but it required system authorization, so it is an NO GO for me.
Do you know how I can do so using the intent?
EDIT:
I have solved the issue: My version of Termux was too old and didn't support the intent results...
However, I now have another issue, which is that I only get the result of the command once the command is entirely finished. For example, if my command is a download command, I will get all messages of ETA and % downloaded after 100% has been downloaded.
Any ideas?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|