diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index ac0118b4..109871e4 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -132,6 +132,15 @@
android:name="android.support.PARENT_ACTIVITY"
android:value="org.kde.kdeconnect.UserInterface.MaterialActivity" />
+
+
+
Use your phone as a mouse and keyboard
Multimedia controls
Control audio/video from your phone
+ Run Command
+ Runs a command on your system
Ping
Send and receive pings
Notification sync
diff --git a/src/org/kde/kdeconnect/NetworkPackage.java b/src/org/kde/kdeconnect/NetworkPackage.java
index 919d1579..4ffef214 100644
--- a/src/org/kde/kdeconnect/NetworkPackage.java
+++ b/src/org/kde/kdeconnect/NetworkPackage.java
@@ -61,6 +61,7 @@ public class NetworkPackage {
public final static String PACKAGE_TYPE_SHARE = "kdeconnect.share";
public static final String PACKAGE_TYPE_CAPABILITIES = "kdeconnect.capabilities";
public final static String PACKAGE_TYPE_FINDMYPHONE = "kdeconnect.findmyphone" ;
+ public final static String PACKAGE_TYPE_RUNCOMMAND = "kdeconnect.runcommand";
private long mId;
private String mType;
diff --git a/src/org/kde/kdeconnect/Plugins/PluginFactory.java b/src/org/kde/kdeconnect/Plugins/PluginFactory.java
index 80e40f3c..eb2b1ed1 100644
--- a/src/org/kde/kdeconnect/Plugins/PluginFactory.java
+++ b/src/org/kde/kdeconnect/Plugins/PluginFactory.java
@@ -28,6 +28,7 @@ import org.kde.kdeconnect.Device;
import org.kde.kdeconnect.Plugins.BatteryPlugin.BatteryPlugin;
import org.kde.kdeconnect.Plugins.FindMyPhonePlugin.FindMyPhonePlugin;
import org.kde.kdeconnect.Plugins.MousePadPlugin.MousePadPlugin;
+import org.kde.kdeconnect.Plugins.RunCommandPlugin.RunCommandPlugin;
import org.kde.kdeconnect.Plugins.SftpPlugin.SftpPlugin;
import org.kde.kdeconnect.Plugins.ClibpoardPlugin.ClipboardPlugin;
import org.kde.kdeconnect.Plugins.MprisPlugin.MprisPlugin;
@@ -123,6 +124,7 @@ public class PluginFactory {
PluginFactory.registerPlugin(SharePlugin.class);
PluginFactory.registerPlugin(TelepathyPlugin.class);
PluginFactory.registerPlugin(FindMyPhonePlugin.class);
+ PluginFactory.registerPlugin(RunCommandPlugin.class);
}
public static PluginInfo getPluginInfo(Context context, String pluginKey) {
diff --git a/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandActivity.java b/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandActivity.java
new file mode 100644
index 00000000..1d90501d
--- /dev/null
+++ b/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandActivity.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2015 Aleix Pol Gonzalez
+ * Copyright 2015 Albert Vaca Cintora
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License or (at your option) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+*/
+
+package org.kde.kdeconnect.Plugins.RunCommandPlugin;
+
+import android.os.Bundle;
+import android.support.v7.app.ActionBarActivity;
+import android.util.Log;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ListView;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.kde.kdeconnect.BackgroundService;
+import org.kde.kdeconnect.Device;
+import org.kde.kdeconnect.UserInterface.List.EntryItem;
+import org.kde.kdeconnect.UserInterface.List.ListAdapter;
+import org.kde.kdeconnect_tp.R;
+
+import java.util.ArrayList;
+
+public class RunCommandActivity extends ActionBarActivity {
+
+ private String deviceId;
+
+ private void updateView() {
+ BackgroundService.RunCommand(this, new BackgroundService.InstanceCallback() {
+ @Override
+ public void onServiceStart(final BackgroundService service) {
+
+ final Device device = service.getDevice(deviceId);
+ final RunCommandPlugin plugin = device.getPlugin(RunCommandPlugin.class);
+ if (plugin == null) {
+ Log.e("RunCommandActivity", "device has no runcommand plugin!");
+ return;
+ }
+
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ ListView view = (ListView) findViewById(R.id.listView1);
+
+ final ArrayList commands = plugin.getCommandList();
+
+ ArrayList commandItems = new ArrayList<>();
+ for (JSONObject obj : commands) {
+ try {
+ Log.e("cacaca", obj.toString());
+ commandItems.add(new EntryItem(obj.getString("name"), obj.getString("command")));
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ ListAdapter adapter = new ListAdapter(RunCommandActivity.this, commandItems);
+
+ view.setAdapter(adapter);
+ view.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> adapterView, View view, int i, long l) {
+ try {
+ Log.e("fu", commands.get(i).getString("command"));
+ plugin.runCommand(commands.get(i).getString("key"));
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+ });
+ }
+ });
+ }
+
+ private final RunCommandPlugin.CommandsChangedCallback theCallback = new RunCommandPlugin.CommandsChangedCallback() {
+ @Override
+ public void update() {
+ updateView();
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_list);
+
+ deviceId = getIntent().getStringExtra("deviceId");
+
+ updateView();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ BackgroundService.RunCommand(this, new BackgroundService.InstanceCallback() {
+ @Override
+ public void onServiceStart(final BackgroundService service) {
+
+ final Device device = service.getDevice(deviceId);
+ final RunCommandPlugin plugin = device.getPlugin(RunCommandPlugin.class);
+ if (plugin == null) {
+ Log.e("RunCommandActivity", "device has no runcommand plugin!");
+ return;
+ }
+ plugin.addCommandsUpdatedCallback(theCallback);
+ }
+ });
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ BackgroundService.RunCommand(this, new BackgroundService.InstanceCallback() {
+ @Override
+ public void onServiceStart(final BackgroundService service) {
+
+ final Device device = service.getDevice(deviceId);
+ final RunCommandPlugin plugin = device.getPlugin(RunCommandPlugin.class);
+ if (plugin == null) {
+ Log.e("RunCommandActivity", "device has no runcommand plugin!");
+ return;
+ }
+ plugin.removeCommandsUpdatedCallback(theCallback);
+ }
+ });
+ }
+}
diff --git a/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandPlugin.java b/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandPlugin.java
new file mode 100644
index 00000000..fdee4cd1
--- /dev/null
+++ b/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandPlugin.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2015 Aleix Pol Gonzalez
+ * Copyright 2015 Albert Vaca Cintora
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License or (at your option) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+*/
+
+package org.kde.kdeconnect.Plugins.RunCommandPlugin;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.support.v4.content.ContextCompat;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.kde.kdeconnect.NetworkPackage;
+import org.kde.kdeconnect.Plugins.Plugin;
+import org.kde.kdeconnect_tp.R;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+public class RunCommandPlugin extends Plugin {
+
+ private ArrayList commandList = new ArrayList<>();
+ private ArrayList callbacks = new ArrayList<>();
+
+ public void addCommandsUpdatedCallback(CommandsChangedCallback newCallback) {
+ callbacks.add(newCallback);
+ }
+
+ public void removeCommandsUpdatedCallback(CommandsChangedCallback theCallback) {
+ callbacks.remove(theCallback);
+ }
+
+ interface CommandsChangedCallback {
+ void update();
+ };
+
+ public ArrayList getCommandList() {
+ return commandList;
+ }
+
+ @Override
+ public String getDisplayName() {
+ return context.getResources().getString(R.string.pref_plugin_runcommand);
+ }
+
+ @Override
+ public String getDescription() {
+ return context.getResources().getString(R.string.pref_plugin_runcommand_desc);
+ }
+
+ @Override
+ public Drawable getIcon() {
+ return ContextCompat.getDrawable(context, R.drawable.runcommand_plugin_icon);
+ }
+
+ @Override
+ public boolean onCreate() {
+ requestCommandList();
+ return true;
+ }
+
+ @Override
+ public boolean onPackageReceived(NetworkPackage np) {
+ if (!np.getType().equals(NetworkPackage.PACKAGE_TYPE_RUNCOMMAND)) return false;
+
+ if (np.has("commandList")) {
+ commandList.clear();
+ try {
+ JSONObject obj = new JSONObject(np.getString("commandList"));
+ Iterator keys = obj.keys();
+ while(keys.hasNext()){
+ String s = keys.next();
+ JSONObject o = obj.getJSONObject(s);
+ o.put("key", s);
+ commandList.add(o);
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ for (CommandsChangedCallback aCallback : callbacks) {
+ aCallback.update();
+ }
+
+ device.onPluginsChanged();
+
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public String[] getSupportedPackageTypes() {
+ return new String[]{NetworkPackage.PACKAGE_TYPE_RUNCOMMAND};
+ }
+
+ @Override
+ public String[] getOutgoingPackageTypes() {
+ return new String[]{NetworkPackage.PACKAGE_TYPE_RUNCOMMAND};
+ }
+
+ public void runCommand(String cmdKey) {
+ NetworkPackage np = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_RUNCOMMAND);
+ np.set("key", cmdKey);
+ device.sendPackage(np);
+ }
+
+ private void requestCommandList() {
+ NetworkPackage np = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_RUNCOMMAND);
+ np.set("requestCommandList", true);
+ device.sendPackage(np);
+ }
+
+ @Override
+ public boolean hasMainActivity() {
+ return !commandList.isEmpty();
+ }
+
+ @Override
+ public void startMainActivity(Activity parentActivity) {
+ Intent intent = new Intent(parentActivity, RunCommandActivity.class);
+ intent.putExtra("deviceId", device.getDeviceId());
+ parentActivity.startActivity(intent);
+ }
+
+ @Override
+ public String getActionName() {
+ return context.getString(R.string.pref_plugin_runcommand);
+ }
+
+}