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); + } + +}