diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 30cd194d..af3ab818 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -202,7 +202,7 @@ android:value="org.kde.kdeconnect.UserInterface.MainActivity" /> diff --git a/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandPlugin.java b/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandPlugin.java index 86d25f33..e10ed648 100644 --- a/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandPlugin.java +++ b/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandPlugin.java @@ -7,6 +7,8 @@ package org.kde.kdeconnect.Plugins.RunCommandPlugin; +import static org.kde.kdeconnect.Plugins.RunCommandPlugin.RunCommandWidgetProviderKt.forceRefreshWidgets; + import android.app.Activity; import android.content.Context; import android.content.Intent; @@ -129,8 +131,7 @@ public class RunCommandPlugin extends Plugin { sharedPreferences.edit().putString(KEY_COMMANDS_PREFERENCE + device.getDeviceId(), array.toString()).apply(); } - Intent updateWidget = new Intent(context, RunCommandWidget.class); - context.sendBroadcast(updateWidget); + forceRefreshWidgets(context); } catch (JSONException e) { Log.e("RunCommand", "Error parsing JSON", e); diff --git a/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidget.java b/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidget.java deleted file mode 100644 index 0536e1f5..00000000 --- a/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidget.java +++ /dev/null @@ -1,149 +0,0 @@ -package org.kde.kdeconnect.Plugins.RunCommandPlugin; - -import android.app.PendingIntent; -import android.appwidget.AppWidgetManager; -import android.appwidget.AppWidgetProvider; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.text.TextUtils; -import android.util.Log; -import android.view.View; -import android.widget.RemoteViews; - -import org.kde.kdeconnect.Device; -import org.kde.kdeconnect.KdeConnect; -import org.kde.kdeconnect_tp.R; - -import java.util.concurrent.ConcurrentHashMap; - -public class RunCommandWidget extends AppWidgetProvider { - - 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); - - RunCommandPlugin plugin = KdeConnect.getInstance().getDevicePlugin(targetDevice, 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); - } - - try { - // FIXME: Remove the need for a background service, we are not allowed to start them in API 31+ - final Intent newIntent = new Intent(context, RunCommandWidgetDataProviderService.class); - context.startService(newIntent); - updateWidget(context); - } catch(IllegalStateException exception) { // Meant to catch BackgroundServiceStartNotAllowedException on API 31+ - exception.printStackTrace(); - } - } - - private void setCurrentDevice(final Context context) { - Intent popup = new Intent(context, RunCommandWidgetDeviceSelector.class); - popup.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - - context.startActivity(popup); - } - - public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { - updateWidget(context); - } - - private void updateWidget(final Context context) { - - Device device = getCurrentDevice(); - - if (device == null || !device.isReachable()) { - ConcurrentHashMap devices = KdeConnect.getInstance().getDevices(); - if (devices.size() > 0) { - currentDeviceId = devices.elements().nextElement().getDeviceId(); - } - } - - updateWidgetImpl(context); - } - - private void updateWidgetImpl(Context context) { - - try { - - AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); - int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, RunCommandWidget.class)); - RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_remotecommandplugin); - - PendingIntent pendingIntent; - Intent intent; - - intent = new Intent(context, RunCommandWidget.class); - intent.setAction(SET_CURRENT_DEVICE); - pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); - views.setOnClickPendingIntent(R.id.runcommandWidgetTitleHeader, pendingIntent); - - Device device = getCurrentDevice(); - if (device == null || !device.isReachable()) { - views.setTextViewText(R.id.runcommandWidgetTitle, context.getString(R.string.kde_connect)); - views.setViewVisibility(R.id.run_commands_list, View.GONE); - views.setViewVisibility(R.id.not_reachable_message, View.VISIBLE); - } else { - views.setTextViewText(R.id.runcommandWidgetTitle, device.getName()); - views.setViewVisibility(R.id.run_commands_list, View.VISIBLE); - views.setViewVisibility(R.id.not_reachable_message, View.GONE); - } - - for (int appWidgetId : appWidgetIds) { - - intent = new Intent(context, RunCommandWidgetDataProviderService.class); - intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); - intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); - views.setRemoteAdapter(R.id.run_commands_list, intent); - - intent = new Intent(context, RunCommandWidget.class); - pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); - views.setPendingIntentTemplate(R.id.run_commands_list, pendingIntent); - - AppWidgetManager.getInstance(context).updateAppWidget(appWidgetId, views); - AppWidgetManager.getInstance(context).notifyAppWidgetViewDataChanged(appWidgetId, R.id.run_commands_list); - - } - - } catch (Exception ex) { - Log.e("RunCommandWidget", "Error updating widget", ex); - } - - - KdeConnect.getInstance().addDeviceListChangedCallback("RunCommandWidget", () -> { - Intent updateWidget = new Intent(context, RunCommandWidget.class); - context.sendBroadcast(updateWidget); - }); - } - - public static Device getCurrentDevice() { - return KdeConnect.getInstance().getDevice(currentDeviceId); - } - - public static void setCurrentDevice(final String DeviceId) { - currentDeviceId = DeviceId; - } -} \ No newline at end of file diff --git a/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidgetConfig.kt b/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidgetConfig.kt new file mode 100644 index 00000000..1a670203 --- /dev/null +++ b/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidgetConfig.kt @@ -0,0 +1,85 @@ +package org.kde.kdeconnect.Plugins.RunCommandPlugin + +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.view.View +import android.view.ViewGroup +import android.view.Window +import android.widget.ArrayAdapter +import android.widget.ImageView +import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import org.kde.kdeconnect.Device +import org.kde.kdeconnect.KdeConnect +import org.kde.kdeconnect_tp.R +import org.kde.kdeconnect_tp.databinding.WidgetRemoteCommandPluginDialogBinding +import kotlin.streams.toList + +class RunCommandWidgetConfig : AppCompatActivity() { + + private var appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + + override fun onCreate(bundle: Bundle?) { + super.onCreate(bundle) + + setResult(RESULT_CANCELED) // Default result + + appWidgetId = intent.extras?.getInt(EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID) ?: AppWidgetManager.INVALID_APPWIDGET_ID + if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { + finish() + return + } + + supportRequestWindowFeature(Window.FEATURE_NO_TITLE) + + val binding = WidgetRemoteCommandPluginDialogBinding.inflate(layoutInflater) + setContentView(binding.root) + + val pairedDevices = KdeConnect.getInstance().devices.values.stream().filter(Device::isPaired).toList() + + binding.runCommandsDeviceList.adapter = object : ArrayAdapter(this, 0, pairedDevices) { + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + val view : View = convertView ?: layoutInflater.inflate(R.layout.list_item_with_icon_entry, parent, false) + val device = pairedDevices[position] + view.findViewById(R.id.list_item_entry_title).text = device.name + view.findViewById(R.id.list_item_entry_icon).setImageDrawable(device.icon) + return view + } + } + binding.runCommandsDeviceList.setOnItemClickListener { _, _, position, _ -> + val deviceId = pairedDevices[position].deviceId + saveWidgetDeviceIdPref(this, appWidgetId, deviceId) + + val appWidgetManager = AppWidgetManager.getInstance(this) + updateAppWidget(this, appWidgetManager, appWidgetId) + + val resultValue = Intent() + resultValue.putExtra(EXTRA_APPWIDGET_ID, appWidgetId) + setResult(RESULT_OK, resultValue) + finish() + } + } +} + +private const val PREFS_NAME = "org.kde.kdeconnect_tp.WidgetProvider" +private const val PREF_PREFIX_KEY = "appwidget_" + +internal fun saveWidgetDeviceIdPref(context: Context, appWidgetId: Int, deviceName: String) { + val prefs = context.getSharedPreferences(PREFS_NAME, 0).edit() + prefs.putString(PREF_PREFIX_KEY + appWidgetId, deviceName) + prefs.apply() +} + +internal fun loadWidgetDeviceIdPref(context: Context, appWidgetId: Int): String? { + val prefs = context.getSharedPreferences(PREFS_NAME, 0) + return prefs.getString(PREF_PREFIX_KEY + appWidgetId, null) +} + +internal fun deleteWidgetDeviceIdPref(context: Context, appWidgetId: Int) { + val prefs = context.getSharedPreferences(PREFS_NAME, 0).edit() + prefs.remove(PREF_PREFIX_KEY + appWidgetId) + prefs.apply() +} diff --git a/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidgetDataProvider.java b/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidgetDataProvider.java deleted file mode 100644 index 5ea099e4..00000000 --- a/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidgetDataProvider.java +++ /dev/null @@ -1,94 +0,0 @@ -package org.kde.kdeconnect.Plugins.RunCommandPlugin; - -import android.content.Context; -import android.content.Intent; -import android.view.View; -import android.widget.RemoteViews; -import android.widget.RemoteViewsService; - -import org.kde.kdeconnect_tp.R; - -import java.util.ArrayList; - - -class RunCommandWidgetDataProvider implements RemoteViewsService.RemoteViewsFactory { - - private final Context mContext; - - public RunCommandWidgetDataProvider(Context context, Intent intent) { - mContext = context; - } - - private boolean checkPlugin() { - return RunCommandWidget.getCurrentDevice() != null && RunCommandWidget.getCurrentDevice().isReachable() && RunCommandWidget.getCurrentDevice().getPlugin(RunCommandPlugin.class) != null; - } - - @Override - public void onCreate() { - } - - @Override - public void onDataSetChanged() { - - } - - @Override - public void onDestroy() { - } - - @Override - public int getCount() { - return checkPlugin() ? RunCommandWidget.getCurrentDevice().getPlugin(RunCommandPlugin.class).getCommandItems().size() : 0; - } - - @Override - public RemoteViews getViewAt(int i) { - - RemoteViews remoteView = new RemoteViews(mContext.getPackageName(), R.layout.list_item_entry); - - if (checkPlugin() && RunCommandWidget.getCurrentDevice().getPlugin(RunCommandPlugin.class).getCommandItems().size() > i) { - CommandEntry listItem = RunCommandWidget.getCurrentDevice().getPlugin(RunCommandPlugin.class).getCommandItems().get(i); - - final Intent configIntent = new Intent(mContext, RunCommandWidget.class); - configIntent.setAction(RunCommandWidget.RUN_COMMAND_ACTION); - configIntent.putExtra(RunCommandWidget.TARGET_COMMAND, listItem.getKey()); - configIntent.putExtra(RunCommandWidget.TARGET_DEVICE, RunCommandWidget.getCurrentDevice().getDeviceId()); - - remoteView.setTextViewText(R.id.list_item_entry_title, listItem.getName()); - remoteView.setTextViewText(R.id.list_item_entry_summary, listItem.getCommand()); - remoteView.setViewVisibility(R.id.list_item_entry_summary, View.VISIBLE); - - remoteView.setOnClickFillInIntent(R.id.list_item_entry, configIntent); - } - - return remoteView; - } - - @Override - public RemoteViews getLoadingView() { - return null; - } - - @Override - public int getViewTypeCount() { - return 1; - } - - @Override - public long getItemId(int i) { - int id = 0; - if (RunCommandWidget.getCurrentDevice() != null) { - RunCommandPlugin plugin = RunCommandWidget.getCurrentDevice().getPlugin(RunCommandPlugin.class); - if (plugin != null) { - ArrayList items = plugin.getCommandItems(); - id = items.get(i).getKey().hashCode(); - } - } - return id; - } - - @Override - public boolean hasStableIds() { - return false; - } -} \ No newline at end of file diff --git a/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidgetDataProvider.kt b/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidgetDataProvider.kt new file mode 100644 index 00000000..1fb1fbf4 --- /dev/null +++ b/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidgetDataProvider.kt @@ -0,0 +1,83 @@ +package org.kde.kdeconnect.Plugins.RunCommandPlugin + +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID +import android.content.Context +import android.content.Intent +import android.util.Log +import android.view.View +import android.widget.RemoteViews +import android.widget.RemoteViewsService +import android.widget.RemoteViewsService.RemoteViewsFactory +import org.kde.kdeconnect.KdeConnect +import org.kde.kdeconnect_tp.R + +internal class RunCommandWidgetDataProvider(private val context: Context, val intent: Intent?) : RemoteViewsFactory { + + private lateinit var deviceId : String + private var widgetId : Int = AppWidgetManager.INVALID_APPWIDGET_ID + + override fun onCreate() { + widgetId = intent?.getIntExtra(EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID) ?: AppWidgetManager.INVALID_APPWIDGET_ID + if (widgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { + Log.e("KDEConnect/Widget", "RunCommandWidgetDataProvider: No widget id extra set") + return + } + deviceId = loadWidgetDeviceIdPref(context, widgetId)!! + } + + override fun onDataSetChanged() {} + override fun onDestroy() {} + + override fun getCount(): Int { + return KdeConnect.getInstance().getDevicePlugin(deviceId, RunCommandPlugin::class.java)?.commandItems?.size ?: 0 + } + + override fun getViewAt(i: Int): RemoteViews { + val remoteView = RemoteViews(context.packageName, R.layout.list_item_entry) + + val plugin : RunCommandPlugin? = KdeConnect.getInstance().getDevicePlugin(deviceId, RunCommandPlugin::class.java) + if (plugin == null) { + Log.e("getViewAt", "RunCommandWidgetDataProvider: Plugin not found"); + return remoteView + } + + val listItem = plugin.commandItems[i] + + remoteView.setTextViewText(R.id.list_item_entry_title, listItem.name) + remoteView.setTextViewText(R.id.list_item_entry_summary, listItem.command) + remoteView.setViewVisibility(R.id.list_item_entry_summary, View.VISIBLE) + + val runCommandIntent = Intent(context, RunCommandWidgetProvider::class.java) + runCommandIntent.action = RUN_COMMAND_ACTION + runCommandIntent.putExtra(EXTRA_APPWIDGET_ID, widgetId) + runCommandIntent.putExtra(TARGET_COMMAND, listItem.key) + runCommandIntent.putExtra(TARGET_DEVICE, deviceId) + remoteView.setOnClickFillInIntent(R.id.list_item_entry, runCommandIntent) + + return remoteView + } + + override fun getLoadingView(): RemoteViews? { + return null + } + + override fun getViewTypeCount(): Int { + return 1 + } + + override fun getItemId(i: Int): Long { + return KdeConnect.getInstance().getDevicePlugin(deviceId, RunCommandPlugin::class.java)?.commandItems?.get(i)?.key?.hashCode()?.toLong() ?: 0 + } + + override fun hasStableIds(): Boolean { + return false + } +} + +class CommandsRemoteViewsService : RemoteViewsService() { + override fun onGetViewFactory(intent: Intent): RemoteViewsFactory { + return RunCommandWidgetDataProvider(this.applicationContext, intent) + } +} + diff --git a/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidgetDataProviderService.java b/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidgetDataProviderService.java deleted file mode 100644 index 16c4cc89..00000000 --- a/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidgetDataProviderService.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.kde.kdeconnect.Plugins.RunCommandPlugin; - -import android.content.Intent; -import android.widget.RemoteViewsService; - -public class RunCommandWidgetDataProviderService extends RemoteViewsService { - - @Override - public RemoteViewsFactory onGetViewFactory(Intent intent) { - return new RunCommandWidgetDataProvider(this, intent); - } -} diff --git a/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidgetDeviceSelector.java b/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidgetDeviceSelector.java deleted file mode 100644 index 0047f86a..00000000 --- a/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidgetDeviceSelector.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.kde.kdeconnect.Plugins.RunCommandPlugin; - -import android.content.Intent; -import android.os.Bundle; -import android.view.Window; - -import androidx.appcompat.app.AppCompatActivity; - -import org.kde.kdeconnect.Device; -import org.kde.kdeconnect.KdeConnect; -import org.kde.kdeconnect.UserInterface.List.ListAdapter; -import org.kde.kdeconnect_tp.databinding.WidgetRemoteCommandPluginDialogBinding; - -import java.util.Comparator; -import java.util.List; -import java.util.stream.Collectors; - -public class RunCommandWidgetDeviceSelector extends AppCompatActivity { - @Override - protected void onCreate(Bundle bundle) { - super.onCreate(bundle); - - requestWindowFeature(Window.FEATURE_NO_TITLE); - - final WidgetRemoteCommandPluginDialogBinding binding = - WidgetRemoteCommandPluginDialogBinding.inflate(getLayoutInflater()); - setContentView(binding.getRoot()); - - final List deviceItems = KdeConnect.getInstance().getDevices().values().stream() - .filter(Device::isPaired).filter(Device::isReachable) - .map(device -> new CommandEntry(device.getName(), null, device.getDeviceId())) - .sorted(Comparator.comparing(CommandEntry::getName)) - .collect(Collectors.toList()); - - ListAdapter adapter = new ListAdapter(RunCommandWidgetDeviceSelector.this, deviceItems); - - binding.runCommandsDeviceList.setAdapter(adapter); - binding.runCommandsDeviceList.setOnItemClickListener((adapterView, viewContent, i, l) -> { - CommandEntry entry = deviceItems.get(i); - RunCommandWidget.setCurrentDevice(entry.getKey()); - - Intent updateWidget = new Intent(RunCommandWidgetDeviceSelector.this, RunCommandWidget.class); - RunCommandWidgetDeviceSelector.this.sendBroadcast(updateWidget); - - finish(); - }); - } -} \ No newline at end of file diff --git a/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidgetProvider.kt b/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidgetProvider.kt new file mode 100644 index 00000000..91ce92f7 --- /dev/null +++ b/src/org/kde/kdeconnect/Plugins/RunCommandPlugin/RunCommandWidgetProvider.kt @@ -0,0 +1,138 @@ +package org.kde.kdeconnect.Plugins.RunCommandPlugin + +import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID +import android.appwidget.AppWidgetProvider +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.util.Log +import android.view.View +import android.widget.RemoteViews +import org.kde.kdeconnect.Device +import org.kde.kdeconnect.KdeConnect +import org.kde.kdeconnect_tp.BuildConfig +import org.kde.kdeconnect_tp.R + +const val RUN_COMMAND_ACTION = "RUN_COMMAND_ACTION" +const val TARGET_COMMAND = "TARGET_COMMAND" +const val TARGET_DEVICE = "TARGET_DEVICE" +private const val SET_CURRENT_DEVICE = "SET_CURRENT_DEVICE" + +class RunCommandWidgetProvider : AppWidgetProvider() { + + override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) { + for (appWidgetId in appWidgetIds) { + updateAppWidget(context, appWidgetManager, appWidgetId) + } + } + + override fun onDeleted(context: Context, appWidgetIds: IntArray) { + for (appWidgetId in appWidgetIds) { + deleteWidgetDeviceIdPref(context, appWidgetId) + } + } + + override fun onEnabled(context: Context) { + super.onEnabled(context) + KdeConnect.getInstance().addDeviceListChangedCallback("RunCommandWidget") { + forceRefreshWidgets(context) + } + } + + override fun onDisabled(context: Context) { + KdeConnect.getInstance().removeDeviceListChangedCallback("RunCommandWidget") + super.onDisabled(context) + } + + override fun onReceive(context: Context, intent: Intent) { + super.onReceive(context, intent) + Log.d("WidgetProvider", "onReceive " + intent.action) + + val appWidgetId = intent.getIntExtra(EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID) + if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { + Log.e("KDEConnect/Widget", "No widget id extra set") + return + } + + if (intent.action == RUN_COMMAND_ACTION) { + val targetCommand = intent.getStringExtra(TARGET_COMMAND) + val targetDevice = intent.getStringExtra(TARGET_DEVICE) + val plugin = KdeConnect.getInstance().getDevicePlugin(targetDevice, RunCommandPlugin::class.java) + if (plugin != null) { + try { + plugin.runCommand(targetCommand) + } catch (ex: Exception) { + Log.e("RunCommandWidget", "Error running command", ex) + } + } + } else if (intent.action == SET_CURRENT_DEVICE) { + val popup = Intent(context, RunCommandWidgetConfig::class.java) + popup.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS + popup.putExtra(EXTRA_APPWIDGET_ID, appWidgetId) + context.startActivity(popup) + } + } +} + +fun getAllWidgetIds(context : Context) : IntArray { + return AppWidgetManager.getInstance(context).getAppWidgetIds( + ComponentName(context, RunCommandWidgetProvider::class.java) + ) +} + +fun forceRefreshWidgets(context : Context) { + val intent = Intent(context, RunCommandWidgetProvider::class.java) + intent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE + intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, getAllWidgetIds(context)) + context.sendBroadcast(intent) +} + +internal fun updateAppWidget( + context: Context, + appWidgetManager: AppWidgetManager, + appWidgetId: Int +) { + Log.d("WidgetProvider", "updateAppWidget") + + val deviceId = loadWidgetDeviceIdPref(context, appWidgetId) + val device: Device? = if (deviceId != null) KdeConnect.getInstance().getDevice(deviceId) else null + + val views = RemoteViews(BuildConfig.APPLICATION_ID, R.layout.widget_remotecommandplugin) + val setDeviceIntent = Intent(context, RunCommandWidgetProvider::class.java) + setDeviceIntent.putExtra(EXTRA_APPWIDGET_ID, appWidgetId) + setDeviceIntent.action = SET_CURRENT_DEVICE + val setDevicePendingIntent = PendingIntent.getBroadcast(context,0,setDeviceIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE) + views.setOnClickPendingIntent(R.id.runcommandWidgetTitleHeader, setDevicePendingIntent) + + if (device == null) { + views.setTextViewText(R.id.runcommandWidgetTitle, context.getString(R.string.kde_connect)) + views.setViewVisibility(R.id.run_commands_list, View.VISIBLE) + views.setViewVisibility(R.id.not_reachable_message, View.GONE) + } else { + views.setTextViewText(R.id.runcommandWidgetTitle, device.name) + if (device.isReachable) { + views.setViewVisibility(R.id.run_commands_list, View.VISIBLE) + views.setViewVisibility(R.id.not_reachable_message, View.GONE) + // Configure remote adapter + val dataProviderIntent = Intent(context, CommandsRemoteViewsService::class.java) + dataProviderIntent.putExtra(EXTRA_APPWIDGET_ID, appWidgetId) + dataProviderIntent.data = Uri.parse(dataProviderIntent.toUri(Intent.URI_INTENT_SCHEME)) + views.setRemoteAdapter(R.id.run_commands_list, dataProviderIntent) + // This pending intent allows the remote adapter to call fillInIntent so list items can do things + val runCommandTemplateIntent = Intent(context, RunCommandWidgetProvider::class.java) + runCommandTemplateIntent.action = RUN_COMMAND_ACTION + runCommandTemplateIntent.putExtra(EXTRA_APPWIDGET_ID, appWidgetId) + val runCommandTemplatePendingIntent = PendingIntent.getBroadcast(context, 0, runCommandTemplateIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE) + views.setPendingIntentTemplate(R.id.run_commands_list, runCommandTemplatePendingIntent) + } else { + views.setViewVisibility(R.id.run_commands_list, View.GONE) + views.setViewVisibility(R.id.not_reachable_message, View.VISIBLE) + } + } + + appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.run_commands_list) + appWidgetManager.updateAppWidget(appWidgetId, views) +}