This forum has been archived. All content is frozen. Please use KDE Discuss instead.

KDE Connect Android - Intent Broadcast from external app

Tags: None
(comma "," separated)
Udragg
Registered Member
Posts
1
Karma
0
Hi,
I was curious to see if there was a possibility to use the run command plugin of KDE Connect from automate, an android automation app.
In automate I noticed there was a RunCommandWidget receiver. (An intent broadcast receiver is used to receive inter-app messaging.) Upon looking in the source code (more specifically the file RunCommandWidget.java I saw the onReceive method, the name of which suggests it will be called when a broadcast is sent to it.

onReceive method in RunCommandWidget.java
Code: Select all
public static final String RUN_COMMAND_ACTION = "RUN_COMMAND_ACTION";
public static final String TARGET_COMMAND = "TARGET_COMMAND";
public static final String TARGET_DEVICE = "TARGET_DEVICE";
private static final String SET_CURRENT_DEVICE = "SET_CURRENT_DEVICE";

private static String currentDeviceId;

@Override
public void onReceive(Context context, Intent intent) {

    super.onReceive(context, intent);

    if (intent != null && intent.getAction() != null && intent.getAction().equals(RUN_COMMAND_ACTION)) {

        final String targetCommand = intent.getStringExtra(TARGET_COMMAND);
        final String targetDevice = intent.getStringExtra(TARGET_DEVICE);

        BackgroundService.RunCommand(context, service -> {
            RunCommandPlugin plugin = service.getDevice(targetDevice).getPlugin(RunCommandPlugin.class);

            if (plugin != null) {
                try {

                    plugin.runCommand(targetCommand);
                } catch (Exception ex) {
                    Log.e("RunCommandWidget", "Error running command", ex);
                }
            }
        });
    } else if (intent != null && TextUtils.equals(intent.getAction(), SET_CURRENT_DEVICE)) {
        setCurrentDevice(context);
    }

    final Intent newIntent = new Intent(context, RunCommandWidgetDataProviderService.class);
    context.startService(newIntent);
    updateWidget(context);

}


First the method checks if the intent's action is equal to "RUN_COMMAND_ACTION". This suggests that the action field of the broadcast should be set to RUN_COMMAND_ACTION.
Afterwards the method gets the values for TARGET_COMMAND and TARGET_DEVICE from the intent's extras.
After some searching I found that the extras of an intent is a dictionary, so I assume I have to add two field to said dictionary. One with the key TARGET_COMMAND and the name of the command I want to run as a String for its value. The second with key TARGET_DEVICE and the name of the device as the value.

So when looking at this method it appears the broadcast needs to contain:
  1. RunCommandWidget as its receiver (automate helps with this by providing a list of all valid receivers)
  2. RUN_COMMAND_ACTION as its action
  3. An extra with key TARGET_COMMAND and value "command_name" of type String
  4. An extra with key TARGET_DEVICE and value "device_name" of type String

So I filled in those details in automate as shown in this screenshot.
note: the screenshot shows "TARGET_DEVICE" as String instead of just "TARGET_DEVICE" but I tested both without any difference

However the KDE Connect app crashes every time I execute it. So I went to check the bug report from my phone.
The first crash produced the following exception:
Code: Select all
java.lang.RuntimeException: Unable to start receiver org.kde.kdeconnect.Plugins.RunCommandPlugin.RunCommandWidget: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=org.kde.kdeconnect_tp/org.kde.kdeconnect.Plugins.RunCommandPlugin.RunCommandWidgetDataProviderService }: app is in background

However all crashes afterwards produced a different exception:
Code: Select all
java.lang.RuntimeException: Unable to start service org.kde.kdeconnect.BackgroundService@12887a0 with Intent { cmp=org.kde.kdeconnect_tp/org.kde.kdeconnect.BackgroundService }: java.lang.NullPointerException: Attempt to invoke virtual method 'org.kde.kdeconnect.Plugins.Plugin org.kde.kdeconnect.Device.getPlugin(java.lang.Class)' on a null object reference

I assume the app is crashing on this line in because RunCommandPlugin.class returns null, which causes getPlugin to raise an exception.
RunCommandWidget.java (line 39)
Code: Select all
RunCommandPlugin plugin = service.getDevice(targetDevice).getPlugin(RunCommandPlugin.class);

What I fail to understand is why RunCommandPlugin.class would return a null value (as well as why the first crash is different). The widget itself definitely works on my phone as I've been using it for months.
My best guess at the moment is that the widget on my homescreen initializes other values or runs additional code when I use it to run a command.

I've tried a bit to google how to use RunCommandWidget receiver, but I don't expect anyone else has had such an obscure issue, and the receiver was probably never meant for use outside the widget anyways. (Or maybe I'm just bad at googling, also a reasonable possibility.)
To confirm this I would have to learn the workings of the app (or at least the run commands plugin), something I currently don't really have the time for and which would be slowed down massively by the fact I don't know any java, or a language similar to it for that matter.

Anyways, apologies for any bad formatting or explanations, first time posting.
Regards,
Udragg


Bookmarks



Who is online

Registered users: bartoloni, Bing [Bot], Google [Bot], Yahoo [Bot]