File indexing completed on 2024-12-22 04:41:40

0001 /*
0002  * SPDX-FileCopyrightText: 2015 Aleix Pol Gonzalez <aleixpol@kde.org>
0003  * SPDX-FileCopyrightText: 2015 Albert Vaca Cintora <albertvaka@gmail.com>
0004  *
0005  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0006 */
0007 
0008 package org.kde.kdeconnect.Plugins.RunCommandPlugin;
0009 
0010 import static org.kde.kdeconnect.Plugins.RunCommandPlugin.RunCommandWidgetProviderKt.forceRefreshWidgets;
0011 
0012 import android.app.Activity;
0013 import android.content.Context;
0014 import android.content.Intent;
0015 import android.content.SharedPreferences;
0016 import android.os.Build;
0017 import android.util.Log;
0018 
0019 import androidx.annotation.DrawableRes;
0020 import androidx.annotation.NonNull;
0021 import androidx.annotation.Nullable;
0022 import androidx.preference.PreferenceManager;
0023 
0024 import org.apache.commons.collections4.iterators.IteratorIterable;
0025 import org.json.JSONArray;
0026 import org.json.JSONException;
0027 import org.json.JSONObject;
0028 import org.kde.kdeconnect.NetworkPacket;
0029 import org.kde.kdeconnect.Plugins.Plugin;
0030 import org.kde.kdeconnect.Plugins.PluginFactory;
0031 import org.kde.kdeconnect.UserInterface.PluginSettingsFragment;
0032 import org.kde.kdeconnect_tp.R;
0033 
0034 import java.util.ArrayList;
0035 import java.util.Collections;
0036 import java.util.Comparator;
0037 
0038 @PluginFactory.LoadablePlugin
0039 public class RunCommandPlugin extends Plugin {
0040 
0041     private final static String PACKET_TYPE_RUNCOMMAND = "kdeconnect.runcommand";
0042     private final static String PACKET_TYPE_RUNCOMMAND_REQUEST = "kdeconnect.runcommand.request";
0043     public final static String KEY_COMMANDS_PREFERENCE = "commands_preference_";
0044 
0045     private final ArrayList<JSONObject> commandList = new ArrayList<>();
0046     private final ArrayList<CommandsChangedCallback> callbacks = new ArrayList<>();
0047     private final ArrayList<CommandEntry> commandItems = new ArrayList<>();
0048 
0049     private SharedPreferences sharedPreferences;
0050 
0051     private boolean canAddCommand;
0052 
0053     public void addCommandsUpdatedCallback(CommandsChangedCallback newCallback) {
0054         callbacks.add(newCallback);
0055     }
0056 
0057     public void removeCommandsUpdatedCallback(CommandsChangedCallback theCallback) {
0058         callbacks.remove(theCallback);
0059     }
0060 
0061     interface CommandsChangedCallback {
0062         void update();
0063     }
0064 
0065     public ArrayList<JSONObject> getCommandList() {
0066         return commandList;
0067     }
0068 
0069     public ArrayList<CommandEntry> getCommandItems() {
0070         return commandItems;
0071     }
0072 
0073     @Override
0074     public @NonNull String getDisplayName() {
0075         return context.getResources().getString(R.string.pref_plugin_runcommand);
0076     }
0077 
0078     @Override
0079     public @NonNull String getDescription() {
0080         return context.getResources().getString(R.string.pref_plugin_runcommand_desc);
0081     }
0082 
0083     @Override
0084     public boolean hasSettings() {
0085         return true;
0086     }
0087 
0088     @Nullable
0089     @Override
0090     public PluginSettingsFragment getSettingsFragment(Activity activity) {
0091         return PluginSettingsFragment.newInstance(getPluginKey(), R.xml.runcommand_preferences);
0092     }
0093 
0094     @Override
0095     public @DrawableRes int getIcon() {
0096         return R.drawable.run_command_plugin_icon_24dp;
0097     }
0098 
0099     @Override
0100     public boolean onCreate() {
0101         sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this.context);
0102         requestCommandList();
0103         return true;
0104     }
0105 
0106     @Override
0107     public boolean onPacketReceived(@NonNull NetworkPacket np) {
0108 
0109         if (np.has("commandList")) {
0110             commandList.clear();
0111             try {
0112                 commandItems.clear();
0113                 JSONObject obj = new JSONObject(np.getString("commandList"));
0114                 for (String s : new IteratorIterable<>(obj.keys())) {
0115                     JSONObject o = obj.getJSONObject(s);
0116                     o.put("key", s);
0117                     commandList.add(o);
0118 
0119                     try {
0120                         commandItems.add(
0121                                 new CommandEntry(o)
0122                         );
0123                     } catch (JSONException e) {
0124                         Log.e("RunCommand", "Error parsing JSON", e);
0125                     }
0126                 }
0127 
0128                 Collections.sort(commandItems, Comparator.comparing(CommandEntry::getName));
0129 
0130                 // Used only by RunCommandControlsProviderService to display controls correctly even when device is not available
0131                 if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
0132                     JSONArray array = new JSONArray();
0133 
0134                     for (JSONObject command : commandList) {
0135                         array.put(command);
0136                     }
0137 
0138                     sharedPreferences.edit()
0139                             .putString(KEY_COMMANDS_PREFERENCE + device.getDeviceId(), array.toString())
0140                             .apply();
0141                 }
0142 
0143                 forceRefreshWidgets(context);
0144 
0145             } catch (JSONException e) {
0146                 Log.e("RunCommand", "Error parsing JSON", e);
0147             }
0148 
0149             for (CommandsChangedCallback aCallback : callbacks) {
0150                 aCallback.update();
0151             }
0152 
0153             device.onPluginsChanged();
0154 
0155             canAddCommand = np.getBoolean("canAddCommand", false);
0156 
0157             return true;
0158         }
0159         return false;
0160     }
0161 
0162     @Override
0163     public @NonNull String[] getSupportedPacketTypes() {
0164         return new String[]{PACKET_TYPE_RUNCOMMAND};
0165     }
0166 
0167     @Override
0168     public @NonNull String[] getOutgoingPacketTypes() {
0169         return new String[]{PACKET_TYPE_RUNCOMMAND_REQUEST};
0170     }
0171 
0172     public void runCommand(String cmdKey) {
0173         NetworkPacket np = new NetworkPacket(PACKET_TYPE_RUNCOMMAND_REQUEST);
0174         np.set("key", cmdKey);
0175         device.sendPacket(np);
0176     }
0177 
0178     private void requestCommandList() {
0179         NetworkPacket np = new NetworkPacket(PACKET_TYPE_RUNCOMMAND_REQUEST);
0180         np.set("requestCommandList", true);
0181         device.sendPacket(np);
0182     }
0183 
0184     @Override
0185     public boolean displayAsButton(Context context) {
0186         return true;
0187     }
0188 
0189     @Override
0190     public void startMainActivity(Activity parentActivity) {
0191         Intent intent = new Intent(parentActivity, RunCommandActivity.class);
0192         intent.putExtra("deviceId", device.getDeviceId());
0193         parentActivity.startActivity(intent);
0194     }
0195 
0196     @Override
0197     public @NonNull String getActionName() {
0198         return context.getString(R.string.pref_plugin_runcommand);
0199     }
0200 
0201     public boolean canAddCommand() {
0202         return canAddCommand;
0203     }
0204 
0205     void sendSetupPacket() {
0206         NetworkPacket np = new NetworkPacket(RunCommandPlugin.PACKET_TYPE_RUNCOMMAND_REQUEST);
0207         np.set("setup", true);
0208         device.sendPacket(np);
0209     }
0210 
0211 }