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 }