mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-08-22 01:51:47 +00:00
Allow having widgets for more than once device
Rewrites the RunCommand widget. Now we can have different widgets for different devices at the same time. Also removes the startService call that could cause ForegroundServiceStartNotAllowedException on API 12+.
This commit is contained in:
parent
2fda82cd02
commit
11634b2cde
@ -202,7 +202,7 @@
|
||||
android:value="org.kde.kdeconnect.UserInterface.MainActivity" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name="org.kde.kdeconnect.Plugins.RunCommandPlugin.RunCommandWidgetDeviceSelector"
|
||||
android:name="org.kde.kdeconnect.Plugins.RunCommandPlugin.RunCommandWidgetConfig"
|
||||
android:excludeFromRecents="true"
|
||||
android:label="@string/pref_plugin_runcommand"
|
||||
android:launchMode="singleTask"
|
||||
@ -211,12 +211,12 @@
|
||||
android:theme="@style/Theme.AppCompat.Light.Dialog" />
|
||||
|
||||
<service
|
||||
android:name="org.kde.kdeconnect.Plugins.RunCommandPlugin.RunCommandWidgetDataProviderService"
|
||||
android:name="org.kde.kdeconnect.Plugins.RunCommandPlugin.CommandsRemoteViewsService"
|
||||
android:exported="false"
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||
|
||||
<receiver
|
||||
android:name="org.kde.kdeconnect.Plugins.RunCommandPlugin.RunCommandWidget"
|
||||
android:name="org.kde.kdeconnect.Plugins.RunCommandPlugin.RunCommandWidgetProvider"
|
||||
android:label="@string/pref_plugin_runcommand"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
|
@ -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);
|
||||
|
@ -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<String, Device> 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;
|
||||
}
|
||||
}
|
@ -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<Device>(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<TextView>(R.id.list_item_entry_title).text = device.name
|
||||
view.findViewById<ImageView>(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()
|
||||
}
|
@ -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<CommandEntry> items = plugin.getCommandItems();
|
||||
id = items.get(i).getKey().hashCode();
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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<CommandEntry> 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();
|
||||
});
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user