'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