mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-08-22 18:07:55 +00:00
Refactor BackgroundService
Added a new KdeConnect Application class that holds the Devices now, while BackgroundService "only" takes care of the LinkProviders. Since KdeConnect subclasses Application we have the guarantee that it will exist as long as our process does, so we can use it as a singleton. This removes the "BackgroundService.RunCommand" hack (which sent an Intent that would awake BackgroundService in case it wasn't running already and then call our code in a callback). This saves lots of round trips between the system and us and makes things simpler (and stack traces useful) by making the code sequential. We already had an Application subclass that I moved to a new helper, which now the KdeConnect class initializes together with all the other helpers.
This commit is contained in:
parent
a6eea8e996
commit
ae23413971
@ -52,7 +52,7 @@
|
|||||||
android:networkSecurityConfig="@xml/network_security_config"
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
android:localeConfig="@xml/locales_config"
|
android:localeConfig="@xml/locales_config"
|
||||||
android:theme="@style/KdeConnectTheme.NoActionBar"
|
android:theme="@style/KdeConnectTheme.NoActionBar"
|
||||||
android:name="org.kde.kdeconnect.MyApplication"
|
android:name="org.kde.kdeconnect.KdeConnect"
|
||||||
android:enableOnBackInvokedCallback="true">
|
android:enableOnBackInvokedCallback="true">
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
|
@ -53,11 +53,6 @@ public abstract class BaseLink {
|
|||||||
return linkProvider;
|
return linkProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
//The daemon will periodically destroy unpaired links if this returns false
|
|
||||||
public boolean linkShouldBeKeptAlive() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addPacketReceiver(PacketReceiver pr) {
|
public void addPacketReceiver(PacketReceiver pr) {
|
||||||
receivers.add(pr);
|
receivers.add(pr);
|
||||||
}
|
}
|
||||||
|
@ -186,11 +186,6 @@ public class BluetoothLink extends BaseLink {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean linkShouldBeKeptAlive() {
|
|
||||||
return receivingThread.isAlive();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
public boolean isConnected() {
|
public boolean isConnected() {
|
||||||
return socket.isConnected();
|
return socket.isConnected();
|
||||||
|
@ -252,14 +252,4 @@ public class LanLink extends BaseLink {
|
|||||||
packetReceived(np);
|
packetReceived(np);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean linkShouldBeKeptAlive() {
|
|
||||||
|
|
||||||
return true; //FIXME: Current implementation is broken, so for now we will keep links always established
|
|
||||||
|
|
||||||
//We keep the remotely initiated connections, since the remotes require them if they want to request
|
|
||||||
//pairing to us, or connections that are already paired.
|
|
||||||
//return (connectionSource == ConnectionStarted.Remotely);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -14,12 +14,12 @@ import android.util.Log;
|
|||||||
|
|
||||||
import org.kde.kdeconnect.Backends.BaseLink;
|
import org.kde.kdeconnect.Backends.BaseLink;
|
||||||
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
|
||||||
import org.kde.kdeconnect.Device;
|
import org.kde.kdeconnect.Device;
|
||||||
import org.kde.kdeconnect.Helpers.DeviceHelper;
|
import org.kde.kdeconnect.Helpers.DeviceHelper;
|
||||||
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
|
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
|
||||||
import org.kde.kdeconnect.Helpers.ThreadHelper;
|
import org.kde.kdeconnect.Helpers.ThreadHelper;
|
||||||
import org.kde.kdeconnect.Helpers.TrustedNetworkHelper;
|
import org.kde.kdeconnect.Helpers.TrustedNetworkHelper;
|
||||||
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect.NetworkPacket;
|
import org.kde.kdeconnect.NetworkPacket;
|
||||||
import org.kde.kdeconnect.UserInterface.CustomDevicesActivity;
|
import org.kde.kdeconnect.UserInterface.CustomDevicesActivity;
|
||||||
|
|
||||||
@ -196,13 +196,13 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
|
|||||||
|
|
||||||
if (isDeviceTrusted && !SslHelper.isCertificateStored(context, deviceId)) {
|
if (isDeviceTrusted && !SslHelper.isCertificateStored(context, deviceId)) {
|
||||||
//Device paired with and old version, we can't use it as we lack the certificate
|
//Device paired with and old version, we can't use it as we lack the certificate
|
||||||
BackgroundService.RunCommand(context, service -> {
|
Device device = KdeConnect.getInstance().getDevice(deviceId);
|
||||||
Device device = service.getDevice(deviceId);
|
if (device == null) {
|
||||||
if (device == null) return;
|
return;
|
||||||
|
}
|
||||||
device.unpair();
|
device.unpair();
|
||||||
//Retry as unpaired
|
//Retry as unpaired
|
||||||
identityPacketReceived(identityPacket, socket, connectionStarted);
|
identityPacketReceived(identityPacket, socket, connectionStarted);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i("KDE/LanLinkProvider", "Starting SSL handshake with " + identityPacket.getString("deviceName") + " trusted:" + isDeviceTrusted);
|
Log.i("KDE/LanLinkProvider", "Starting SSL handshake with " + identityPacket.getString("deviceName") + " trusted:" + isDeviceTrusted);
|
||||||
@ -217,11 +217,11 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
|
|||||||
addLink(identityPacket, sslsocket, connectionStarted);
|
addLink(identityPacket, sslsocket, connectionStarted);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e("KDE/LanLinkProvider", "Handshake as " + mode + " failed with " + identityPacket.getString("deviceName"), e);
|
Log.e("KDE/LanLinkProvider", "Handshake as " + mode + " failed with " + identityPacket.getString("deviceName"), e);
|
||||||
BackgroundService.RunCommand(context, service -> {
|
Device device = KdeConnect.getInstance().getDevice(deviceId);
|
||||||
Device device = service.getDevice(deviceId);
|
if (device == null) {
|
||||||
if (device == null) return;
|
return;
|
||||||
|
}
|
||||||
device.unpair();
|
device.unpair();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//Handshake is blocking, so do it on another thread and free this thread to keep receiving new connection
|
//Handshake is blocking, so do it on another thread and free this thread to keep receiving new connection
|
||||||
|
@ -14,34 +14,26 @@ import android.app.Service;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ServiceInfo;
|
import android.content.pm.ServiceInfo;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.Network;
|
import android.net.Network;
|
||||||
import android.net.NetworkCapabilities;
|
import android.net.NetworkCapabilities;
|
||||||
import android.net.NetworkRequest;
|
import android.net.NetworkRequest;
|
||||||
import android.os.Binder;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.lifecycle.LiveData;
|
||||||
|
import androidx.lifecycle.MutableLiveData;
|
||||||
|
|
||||||
import org.kde.kdeconnect.Backends.BaseLink;
|
|
||||||
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
||||||
import org.kde.kdeconnect.Backends.LanBackend.LanLinkProvider;
|
import org.kde.kdeconnect.Backends.LanBackend.LanLinkProvider;
|
||||||
import org.kde.kdeconnect.Helpers.DeviceHelper;
|
|
||||||
import org.kde.kdeconnect.Helpers.NotificationHelper;
|
import org.kde.kdeconnect.Helpers.NotificationHelper;
|
||||||
import org.kde.kdeconnect.Helpers.SecurityHelpers.RsaHelper;
|
|
||||||
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
|
|
||||||
import org.kde.kdeconnect.Helpers.ThreadHelper;
|
|
||||||
import org.kde.kdeconnect.Plugins.ClibpoardPlugin.ClipboardFloatingActivity;
|
import org.kde.kdeconnect.Plugins.ClibpoardPlugin.ClipboardFloatingActivity;
|
||||||
import org.kde.kdeconnect.Plugins.Plugin;
|
|
||||||
import org.kde.kdeconnect.Plugins.PluginFactory;
|
|
||||||
import org.kde.kdeconnect.Plugins.RunCommandPlugin.RunCommandActivity;
|
import org.kde.kdeconnect.Plugins.RunCommandPlugin.RunCommandActivity;
|
||||||
import org.kde.kdeconnect.Plugins.RunCommandPlugin.RunCommandPlugin;
|
import org.kde.kdeconnect.Plugins.RunCommandPlugin.RunCommandPlugin;
|
||||||
import org.kde.kdeconnect.Plugins.SharePlugin.SendFileActivity;
|
import org.kde.kdeconnect.Plugins.SharePlugin.SendFileActivity;
|
||||||
@ -49,92 +41,34 @@ import org.kde.kdeconnect.UserInterface.MainActivity;
|
|||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.locks.Lock;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
|
|
||||||
//import org.kde.kdeconnect.Backends.BluetoothBackend.BluetoothLinkProvider;
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This class (still) does 3 things:
|
||||||
|
* - Keeps the app running by creating a foreground notification.
|
||||||
|
* - Holds references to the active LinkProviders, but doesn't handle the DeviceLink those create (the KdeConnect class does that).
|
||||||
|
* - Listens for network connectivity changes and tells the LinkProviders to re-check for devices.
|
||||||
|
* It can be started by the KdeConnectBroadcastReceiver on some events or when the MainActivity is launched.
|
||||||
|
*/
|
||||||
public class BackgroundService extends Service {
|
public class BackgroundService extends Service {
|
||||||
private static final int FOREGROUND_NOTIFICATION_ID = 1;
|
private static final int FOREGROUND_NOTIFICATION_ID = 1;
|
||||||
|
|
||||||
private static BackgroundService instance;
|
private static BackgroundService instance;
|
||||||
|
|
||||||
public interface DeviceListChangedCallback {
|
private KdeConnect applicationInstance;
|
||||||
void onDeviceListChanged(boolean isConnectedToNonCellularNetwork);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface PluginCallback<T extends Plugin> {
|
|
||||||
void run(T plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final ConcurrentHashMap<String, DeviceListChangedCallback> deviceListChangedCallbacks = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private final ArrayList<BaseLinkProvider> linkProviders = new ArrayList<>();
|
private final ArrayList<BaseLinkProvider> linkProviders = new ArrayList<>();
|
||||||
|
|
||||||
private final ConcurrentHashMap<String, Device> devices = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private final HashSet<Object> discoveryModeAcquisitions = new HashSet<>();
|
|
||||||
|
|
||||||
public static BackgroundService getInstance() {
|
public static BackgroundService getInstance() {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isConnectedToNonCellularNetwork; // True when connected over wifi/usb/bluetooth/(anything other than cellular)
|
// This indicates when connected over wifi/usb/bluetooth/(anything other than cellular)
|
||||||
|
private final MutableLiveData<Boolean> connectedToNonCellularNetwork = new MutableLiveData<>();
|
||||||
private boolean acquireDiscoveryMode(Object key) {
|
public LiveData<Boolean> isConnectedToNonCellularNetwork() {
|
||||||
boolean wasEmpty = discoveryModeAcquisitions.isEmpty();
|
return connectedToNonCellularNetwork;
|
||||||
discoveryModeAcquisitions.add(key);
|
|
||||||
if (wasEmpty) {
|
|
||||||
onNetworkChange();
|
|
||||||
}
|
|
||||||
//Log.e("acquireDiscoveryMode",key.getClass().getName() +" ["+discoveryModeAcquisitions.size()+"]");
|
|
||||||
return wasEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void releaseDiscoveryMode(Object key) {
|
|
||||||
boolean removed = discoveryModeAcquisitions.remove(key);
|
|
||||||
//Log.e("releaseDiscoveryMode",key.getClass().getName() +" ["+discoveryModeAcquisitions.size()+"]");
|
|
||||||
if (removed && discoveryModeAcquisitions.isEmpty()) {
|
|
||||||
cleanDevices();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isInDiscoveryMode() {
|
|
||||||
//return !discoveryModeAcquisitions.isEmpty();
|
|
||||||
return true; // Keep it always on for now
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Device.PairingCallback devicePairingCallback = new Device.PairingCallback() {
|
|
||||||
@Override
|
|
||||||
public void incomingRequest() {
|
|
||||||
onDeviceListChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void pairingSuccessful() {
|
|
||||||
onDeviceListChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void pairingFailed(String error) {
|
|
||||||
onDeviceListChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unpaired() {
|
|
||||||
onDeviceListChanged();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public void onDeviceListChanged() {
|
|
||||||
for (DeviceListChangedCallback callback : deviceListChangedCallbacks.values()) {
|
|
||||||
callback.onDeviceListChanged(isConnectedToNonCellularNetwork);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateForegroundNotification() {
|
||||||
if (NotificationHelper.isPersistentNotificationEnabled(this)) {
|
if (NotificationHelper.isPersistentNotificationEnabled(this)) {
|
||||||
//Update the foreground notification with the currently connected device list
|
//Update the foreground notification with the currently connected device list
|
||||||
NotificationManager nm = ContextCompat.getSystemService(this, NotificationManager.class);
|
NotificationManager nm = ContextCompat.getSystemService(this, NotificationManager.class);
|
||||||
@ -142,97 +76,14 @@ public class BackgroundService extends Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadRememberedDevicesFromSettings() {
|
|
||||||
//Log.e("BackgroundService", "Loading remembered trusted devices");
|
|
||||||
SharedPreferences preferences = getSharedPreferences("trusted_devices", Context.MODE_PRIVATE);
|
|
||||||
Set<String> trustedDevices = preferences.getAll().keySet();
|
|
||||||
for (String deviceId : trustedDevices) {
|
|
||||||
//Log.e("BackgroundService", "Loading device "+deviceId);
|
|
||||||
if (preferences.getBoolean(deviceId, false)) {
|
|
||||||
Device device = new Device(this, deviceId);
|
|
||||||
devices.put(deviceId, device);
|
|
||||||
device.addPairingCallback(devicePairingCallback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void registerLinkProviders() {
|
private void registerLinkProviders() {
|
||||||
linkProviders.add(new LanLinkProvider(this));
|
linkProviders.add(new LanLinkProvider(this));
|
||||||
// linkProviders.add(new LoopbackLinkProvider(this));
|
// linkProviders.add(new LoopbackLinkProvider(this));
|
||||||
// linkProviders.add(new BluetoothLinkProvider(this));
|
// linkProviders.add(new BluetoothLinkProvider(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArrayList<BaseLinkProvider> getLinkProviders() {
|
|
||||||
return linkProviders;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Device getDevice(String id) {
|
|
||||||
if (id == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return devices.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void cleanDevices() {
|
|
||||||
ThreadHelper.execute(() -> {
|
|
||||||
for (Device d : devices.values()) {
|
|
||||||
if (!d.isPaired() && !d.isPairRequested() && !d.isPairRequestedByPeer() && !d.deviceShouldBeKeptAlive()) {
|
|
||||||
d.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private final BaseLinkProvider.ConnectionReceiver deviceListener = new BaseLinkProvider.ConnectionReceiver() {
|
|
||||||
@Override
|
|
||||||
public void onConnectionReceived(final NetworkPacket identityPacket, final BaseLink link) {
|
|
||||||
|
|
||||||
String deviceId = identityPacket.getString("deviceId");
|
|
||||||
|
|
||||||
Device device = devices.get(deviceId);
|
|
||||||
|
|
||||||
if (device != null) {
|
|
||||||
Log.i("KDE/BackgroundService", "addLink, known device: " + deviceId);
|
|
||||||
device.addLink(identityPacket, link);
|
|
||||||
} else {
|
|
||||||
Log.i("KDE/BackgroundService", "addLink,unknown device: " + deviceId);
|
|
||||||
device = new Device(BackgroundService.this, identityPacket, link);
|
|
||||||
if (device.isPaired() || device.isPairRequested() || device.isPairRequestedByPeer()
|
|
||||||
|| link.linkShouldBeKeptAlive()
|
|
||||||
|| isInDiscoveryMode()) {
|
|
||||||
devices.put(deviceId, device);
|
|
||||||
device.addPairingCallback(devicePairingCallback);
|
|
||||||
} else {
|
|
||||||
device.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onDeviceListChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConnectionLost(BaseLink link) {
|
|
||||||
Device d = devices.get(link.getDeviceId());
|
|
||||||
Log.i("KDE/onConnectionLost", "removeLink, deviceId: " + link.getDeviceId());
|
|
||||||
if (d != null) {
|
|
||||||
d.removeLink(link);
|
|
||||||
if (!d.isReachable() && !d.isPaired()) {
|
|
||||||
//Log.e("onConnectionLost","Removing connection device because it was not paired");
|
|
||||||
devices.remove(link.getDeviceId());
|
|
||||||
d.removePairingCallback(devicePairingCallback);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//Log.d("KDE/onConnectionLost","Removing connection to unknown device");
|
|
||||||
}
|
|
||||||
onDeviceListChanged();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public ConcurrentHashMap<String, Device> getDevices() {
|
|
||||||
return devices;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onNetworkChange() {
|
public void onNetworkChange() {
|
||||||
|
Log.d("KDE/BackgroundService", "onNetworkChange");
|
||||||
for (BaseLinkProvider a : linkProviders) {
|
for (BaseLinkProvider a : linkProviders) {
|
||||||
a.onNetworkChange();
|
a.onNetworkChange();
|
||||||
}
|
}
|
||||||
@ -250,22 +101,14 @@ public class BackgroundService extends Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addDeviceListChangedCallback(String key, DeviceListChangedCallback callback) {
|
|
||||||
deviceListChangedCallbacks.put(key, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeDeviceListChangedCallback(String key) {
|
|
||||||
deviceListChangedCallbacks.remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
//This will called only once, even if we launch the service intent several times
|
//This will called only once, even if we launch the service intent several times
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
Log.d("KdeConnect/BgService", "onCreate");
|
||||||
instance = this;
|
instance = this;
|
||||||
|
|
||||||
DeviceHelper.initializeDeviceId(this);
|
KdeConnect.getInstance().addDeviceListChangedCallback("BackgroundService", this::updateForegroundNotification);
|
||||||
|
|
||||||
// Register screen on listener
|
// Register screen on listener
|
||||||
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
|
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
|
||||||
@ -281,29 +124,19 @@ public class BackgroundService extends Service {
|
|||||||
cm.registerNetworkCallback(networkRequestBuilder.build(), new ConnectivityManager.NetworkCallback() {
|
cm.registerNetworkCallback(networkRequestBuilder.build(), new ConnectivityManager.NetworkCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onAvailable(Network network) {
|
public void onAvailable(Network network) {
|
||||||
isConnectedToNonCellularNetwork = true;
|
connectedToNonCellularNetwork.postValue(true);
|
||||||
onDeviceListChanged();
|
|
||||||
onNetworkChange();
|
onNetworkChange();
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onLost(Network network) {
|
public void onLost(Network network) {
|
||||||
isConnectedToNonCellularNetwork = false;
|
connectedToNonCellularNetwork.postValue(false);
|
||||||
onDeviceListChanged();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Log.i("KDE/BackgroundService", "Service not started yet, initializing...");
|
applicationInstance = KdeConnect.getInstance();
|
||||||
|
|
||||||
PluginFactory.initPluginInfo(getBaseContext());
|
|
||||||
initializeSecurityParameters();
|
|
||||||
NotificationHelper.initializeChannels(this);
|
|
||||||
loadRememberedDevicesFromSettings();
|
|
||||||
migratePluginSettings();
|
|
||||||
registerLinkProviders();
|
registerLinkProviders();
|
||||||
|
addConnectionListener(applicationInstance.getConnectionListener()); // Link Providers need to be already registered
|
||||||
//Link Providers need to be already registered
|
|
||||||
addConnectionListener(deviceListener);
|
|
||||||
|
|
||||||
for (BaseLinkProvider a : linkProviders) {
|
for (BaseLinkProvider a : linkProviders) {
|
||||||
a.onStart();
|
a.onStart();
|
||||||
}
|
}
|
||||||
@ -325,36 +158,11 @@ public class BackgroundService extends Service {
|
|||||||
return networkRequestBuilder;
|
return networkRequestBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void migratePluginSettings() {
|
|
||||||
SharedPreferences globalPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
|
||||||
|
|
||||||
for (String pluginKey : PluginFactory.getAvailablePlugins()) {
|
|
||||||
if (PluginFactory.getPluginInfo(pluginKey).supportsDeviceSpecificSettings()) {
|
|
||||||
Iterator<Device> it = devices.values().iterator();
|
|
||||||
|
|
||||||
while (it.hasNext()) {
|
|
||||||
Device device = it.next();
|
|
||||||
Plugin plugin = PluginFactory.instantiatePluginForDevice(getBaseContext(), pluginKey, device);
|
|
||||||
|
|
||||||
if (plugin == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin.copyGlobalToDeviceSpecificSettings(globalPrefs);
|
|
||||||
if (!it.hasNext()) {
|
|
||||||
plugin.removeSettings(globalPrefs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void changePersistentNotificationVisibility(boolean visible) {
|
public void changePersistentNotificationVisibility(boolean visible) {
|
||||||
NotificationManager nm = ContextCompat.getSystemService(this, NotificationManager.class);
|
|
||||||
if (visible) {
|
if (visible) {
|
||||||
nm.notify(FOREGROUND_NOTIFICATION_ID, createForegroundNotification());
|
updateForegroundNotification();
|
||||||
} else {
|
} else {
|
||||||
stopForeground(true);
|
Stop();
|
||||||
Start(this);
|
Start(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -365,7 +173,7 @@ public class BackgroundService extends Service {
|
|||||||
|
|
||||||
ArrayList<String> connectedDevices = new ArrayList<>();
|
ArrayList<String> connectedDevices = new ArrayList<>();
|
||||||
ArrayList<String> connectedDeviceIds = new ArrayList<>();
|
ArrayList<String> connectedDeviceIds = new ArrayList<>();
|
||||||
for (Device device : getDevices().values()) {
|
for (Device device : applicationInstance.getDevices().values()) {
|
||||||
if (device.isReachable() && device.isPaired()) {
|
if (device.isReachable() && device.isPaired()) {
|
||||||
connectedDeviceIds.add(device.getDeviceId());
|
connectedDeviceIds.add(device.getDeviceId());
|
||||||
connectedDevices.add(device.getName());
|
connectedDevices.add(device.getName());
|
||||||
@ -409,7 +217,7 @@ public class BackgroundService extends Service {
|
|||||||
|
|
||||||
if (connectedDeviceIds.size() == 1) {
|
if (connectedDeviceIds.size() == 1) {
|
||||||
String deviceId = connectedDeviceIds.get(0);
|
String deviceId = connectedDeviceIds.get(0);
|
||||||
Device device = getDevice(deviceId);
|
Device device = KdeConnect.getInstance().getDevice(deviceId);
|
||||||
if (device != null) {
|
if (device != null) {
|
||||||
// Adding two action buttons only when there is a single device connected.
|
// Adding two action buttons only when there is a single device connected.
|
||||||
// Setting up Send File Intent.
|
// Setting up Send File Intent.
|
||||||
@ -432,49 +240,24 @@ public class BackgroundService extends Service {
|
|||||||
return notification.build();
|
return notification.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeSecurityParameters() {
|
|
||||||
RsaHelper.initialiseRsaKeys(this);
|
|
||||||
SslHelper.initialiseCertificate(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
stopForeground(true);
|
Log.d("KdeConnect/BgService", "onDestroy");
|
||||||
for (BaseLinkProvider a : linkProviders) {
|
for (BaseLinkProvider a : linkProviders) {
|
||||||
a.onStop();
|
a.onStop();
|
||||||
}
|
}
|
||||||
|
KdeConnect.getInstance().removeDeviceListChangedCallback("BackgroundService");
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBinder onBind(Intent intent) {
|
public IBinder onBind(Intent intent) {
|
||||||
return new Binder();
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//To use the service from the gui
|
|
||||||
|
|
||||||
public interface InstanceCallback {
|
|
||||||
void onServiceStart(BackgroundService service);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final static ArrayList<InstanceCallback> callbacks = new ArrayList<>();
|
|
||||||
|
|
||||||
private final static Lock mutex = new ReentrantLock(true);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
//This will be called for each intent launch, even if the service is already started and it is reused
|
Log.d("KDE/BackgroundService", "onStartCommand");
|
||||||
mutex.lock();
|
|
||||||
try {
|
|
||||||
for (InstanceCallback c : callbacks) {
|
|
||||||
c.onServiceStart(this);
|
|
||||||
}
|
|
||||||
callbacks.clear();
|
|
||||||
} finally {
|
|
||||||
mutex.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NotificationHelper.isPersistentNotificationEnabled(this)) {
|
if (NotificationHelper.isPersistentNotificationEnabled(this)) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
startForeground(FOREGROUND_NOTIFICATION_ID, createForegroundNotification(), ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE);
|
startForeground(FOREGROUND_NOTIFICATION_ID, createForegroundNotification(), ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE);
|
||||||
@ -482,43 +265,26 @@ public class BackgroundService extends Service {
|
|||||||
startForeground(FOREGROUND_NOTIFICATION_ID, createForegroundNotification());
|
startForeground(FOREGROUND_NOTIFICATION_ID, createForegroundNotification());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (intent.hasExtra("refresh")) {
|
||||||
|
onNetworkChange();
|
||||||
|
}
|
||||||
return Service.START_STICKY;
|
return Service.START_STICKY;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Start(Context c) {
|
public static void Start(Context context) {
|
||||||
RunCommand(c, null);
|
Log.d("KDE/BackgroundService", "Start");
|
||||||
|
ContextCompat.startForegroundService(context, new Intent(context, BackgroundService.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RunCommand(final Context c, final InstanceCallback callback) {
|
public static void ForceRefreshConnections(Context context) {
|
||||||
ThreadHelper.execute(() -> {
|
Log.d("KDE/BackgroundService", "ForceRefreshConnections");
|
||||||
if (callback != null) {
|
Intent i = new Intent(context, BackgroundService.class);
|
||||||
mutex.lock();
|
i.putExtra("refresh", true);
|
||||||
try {
|
ContextCompat.startForegroundService(context, i);
|
||||||
callbacks.add(callback);
|
|
||||||
} finally {
|
|
||||||
mutex.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ContextCompat.startForegroundService(c, new Intent(c, BackgroundService.class));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends Plugin> void RunWithPlugin(final Context c, final String deviceId, final Class<T> pluginClass, final PluginCallback<T> cb) {
|
public void Stop() {
|
||||||
RunCommand(c, service -> {
|
stopForeground(true);
|
||||||
Device device = service.getDevice(deviceId);
|
|
||||||
|
|
||||||
if (device == null) {
|
|
||||||
Log.e("BackgroundService", "Device " + deviceId + " not found");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final T plugin = device.getPlugin(pluginClass);
|
|
||||||
|
|
||||||
if (plugin == null) {
|
|
||||||
Log.e("BackgroundService", "Device " + device.getName() + " does not have plugin " + pluginClass.getName());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cb.run(plugin);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -883,22 +883,6 @@ public class Device implements BaseLink.PacketReceiver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean deviceShouldBeKeptAlive() {
|
|
||||||
|
|
||||||
SharedPreferences preferences = context.getSharedPreferences("trusted_devices", Context.MODE_PRIVATE);
|
|
||||||
if (preferences.contains(getDeviceId())) {
|
|
||||||
//Log.e("DeviceShouldBeKeptAlive", "because it's a paired device");
|
|
||||||
return true; //Already paired
|
|
||||||
}
|
|
||||||
|
|
||||||
for (BaseLink l : links) {
|
|
||||||
if (l.linkShouldBeKeptAlive()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getSupportedPlugins() {
|
public List<String> getSupportedPlugins() {
|
||||||
return supportedPlugins;
|
return supportedPlugins;
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@ import android.os.Build;
|
|||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
import androidx.core.app.NotificationManagerCompat;
|
import androidx.core.app.NotificationManagerCompat;
|
||||||
|
|
||||||
import org.kde.kdeconnect.MyApplication;
|
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
|
|
||||||
public class IntentHelper {
|
public class IntentHelper {
|
||||||
@ -27,8 +26,8 @@ public class IntentHelper {
|
|||||||
* @param intent the Intent to be started
|
* @param intent the Intent to be started
|
||||||
* @param title a title which is shown in the notification on Android 10+
|
* @param title a title which is shown in the notification on Android 10+
|
||||||
*/
|
*/
|
||||||
public static void startActivityFromBackground(Context context, Intent intent, String title) {
|
public static void startActivityFromBackgroundOrCreateNotification(Context context, Intent intent, String title) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && !MyApplication.isInForeground()) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && !LifecycleHelper.isInForeground()) {
|
||||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE);
|
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE);
|
||||||
Notification notification = new NotificationCompat
|
Notification notification = new NotificationCompat
|
||||||
.Builder(context, NotificationHelper.Channels.HIGHPRIORITY)
|
.Builder(context, NotificationHelper.Channels.HIGHPRIORITY)
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
package org.kde.kdeconnect;
|
package org.kde.kdeconnect.Helpers;
|
||||||
|
|
||||||
import android.app.Application;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver;
|
import androidx.lifecycle.DefaultLifecycleObserver;
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import androidx.lifecycle.ProcessLifecycleOwner;
|
import androidx.lifecycle.ProcessLifecycleOwner;
|
||||||
|
|
||||||
import org.kde.kdeconnect.UserInterface.ThemeUtil;
|
public class LifecycleHelper {
|
||||||
|
|
||||||
public class MyApplication extends Application {
|
|
||||||
private static class LifecycleObserver implements DefaultLifecycleObserver {
|
private static class LifecycleObserver implements DefaultLifecycleObserver {
|
||||||
private boolean inForeground = false;
|
private boolean inForeground = false;
|
||||||
|
|
||||||
@ -28,16 +25,13 @@ public class MyApplication extends Application {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final LifecycleObserver foregroundTracker = new LifecycleObserver();
|
private final static LifecycleObserver foregroundTracker = new LifecycleObserver();
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate() {
|
|
||||||
super.onCreate();
|
|
||||||
ThemeUtil.setUserPreferredTheme(this);
|
|
||||||
ProcessLifecycleOwner.get().getLifecycle().addObserver(foregroundTracker);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isInForeground() {
|
public static boolean isInForeground() {
|
||||||
return foregroundTracker.isInForeground();
|
return foregroundTracker.isInForeground();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void initializeObserver() {
|
||||||
|
ProcessLifecycleOwner.get().getLifecycle().addObserver(foregroundTracker);
|
||||||
|
}
|
||||||
}
|
}
|
174
src/org/kde/kdeconnect/KdeConnect.java
Normal file
174
src/org/kde/kdeconnect/KdeConnect.java
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
package org.kde.kdeconnect;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.kde.kdeconnect.Backends.BaseLink;
|
||||||
|
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
||||||
|
import org.kde.kdeconnect.Helpers.DeviceHelper;
|
||||||
|
import org.kde.kdeconnect.Helpers.LifecycleHelper;
|
||||||
|
import org.kde.kdeconnect.Helpers.NotificationHelper;
|
||||||
|
import org.kde.kdeconnect.Helpers.SecurityHelpers.RsaHelper;
|
||||||
|
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
|
||||||
|
import org.kde.kdeconnect.Plugins.Plugin;
|
||||||
|
import org.kde.kdeconnect.Plugins.PluginFactory;
|
||||||
|
import org.kde.kdeconnect.UserInterface.ThemeUtil;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This class holds all the active devices and makes them accessible from every other class.
|
||||||
|
* It also takes care of initializing all classes that need so when the app boots.
|
||||||
|
* It provides a ConnectionReceiver that the BackgroundService uses to ping this class every time a new DeviceLink is created.
|
||||||
|
*/
|
||||||
|
public class KdeConnect extends Application {
|
||||||
|
|
||||||
|
public interface DeviceListChangedCallback {
|
||||||
|
void onDeviceListChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static KdeConnect instance = null;
|
||||||
|
|
||||||
|
private final ConcurrentHashMap<String, Device> devices = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private final ConcurrentHashMap<String, DeviceListChangedCallback> deviceListChangedCallbacks = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
instance = this;
|
||||||
|
Log.d("KdeConnect/Application", "onCreate");
|
||||||
|
ThemeUtil.setUserPreferredTheme(this);
|
||||||
|
DeviceHelper.initializeDeviceId(this);
|
||||||
|
RsaHelper.initialiseRsaKeys(this);
|
||||||
|
SslHelper.initialiseCertificate(this);
|
||||||
|
PluginFactory.initPluginInfo(this);
|
||||||
|
NotificationHelper.initializeChannels(this);
|
||||||
|
LifecycleHelper.initializeObserver();
|
||||||
|
loadRememberedDevicesFromSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTerminate() {
|
||||||
|
Log.d("KdeConnect/Application", "onTerminate");
|
||||||
|
super.onTerminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addDeviceListChangedCallback(String key, DeviceListChangedCallback callback) {
|
||||||
|
deviceListChangedCallbacks.put(key, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeDeviceListChangedCallback(String key) {
|
||||||
|
deviceListChangedCallbacks.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onDeviceListChanged() {
|
||||||
|
for (DeviceListChangedCallback callback : deviceListChangedCallbacks.values()) {
|
||||||
|
callback.onDeviceListChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConcurrentHashMap<String, Device> getDevices() {
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Device getDevice(String id) {
|
||||||
|
if (id == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return devices.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends Plugin> T getDevicePlugin(String deviceId, Class<T> pluginClass) {
|
||||||
|
if (deviceId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Device device = devices.get(deviceId);
|
||||||
|
if (device == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return device.getPlugin(pluginClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KdeConnect getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadRememberedDevicesFromSettings() {
|
||||||
|
//Log.e("BackgroundService", "Loading remembered trusted devices");
|
||||||
|
SharedPreferences preferences = getSharedPreferences("trusted_devices", Context.MODE_PRIVATE);
|
||||||
|
Set<String> trustedDevices = preferences.getAll().keySet();
|
||||||
|
for (String deviceId : trustedDevices) {
|
||||||
|
//Log.e("BackgroundService", "Loading device "+deviceId);
|
||||||
|
if (preferences.getBoolean(deviceId, false)) {
|
||||||
|
Device device = new Device(this, deviceId);
|
||||||
|
devices.put(deviceId, device);
|
||||||
|
device.addPairingCallback(devicePairingCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Device.PairingCallback devicePairingCallback = new Device.PairingCallback() {
|
||||||
|
@Override
|
||||||
|
public void incomingRequest() {
|
||||||
|
onDeviceListChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pairingSuccessful() {
|
||||||
|
onDeviceListChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pairingFailed(String error) {
|
||||||
|
onDeviceListChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unpaired() {
|
||||||
|
onDeviceListChanged();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final BaseLinkProvider.ConnectionReceiver connectionListener = new BaseLinkProvider.ConnectionReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onConnectionReceived(final NetworkPacket identityPacket, final BaseLink link) {
|
||||||
|
String deviceId = identityPacket.getString("deviceId");
|
||||||
|
Device device = devices.get(deviceId);
|
||||||
|
if (device != null) {
|
||||||
|
Log.i("KDE/Application", "addLink, known device: " + deviceId);
|
||||||
|
device.addLink(identityPacket, link);
|
||||||
|
} else {
|
||||||
|
Log.i("KDE/Application", "addLink,unknown device: " + deviceId);
|
||||||
|
device = new Device(KdeConnect.this, identityPacket, link);
|
||||||
|
devices.put(deviceId, device);
|
||||||
|
device.addPairingCallback(devicePairingCallback);
|
||||||
|
}
|
||||||
|
onDeviceListChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnectionLost(BaseLink link) {
|
||||||
|
Device d = devices.get(link.getDeviceId());
|
||||||
|
Log.i("KDE/onConnectionLost", "removeLink, deviceId: " + link.getDeviceId());
|
||||||
|
if (d != null) {
|
||||||
|
d.removeLink(link);
|
||||||
|
if (!d.isReachable() && !d.isPaired()) {
|
||||||
|
//Log.e("onConnectionLost","Removing connection device because it was not paired");
|
||||||
|
devices.remove(link.getDeviceId());
|
||||||
|
d.removePairingCallback(devicePairingCallback);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//Log.d("KDE/onConnectionLost","Removing connection to unknown device");
|
||||||
|
}
|
||||||
|
onDeviceListChanged();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public BaseLinkProvider.ConnectionReceiver getConnectionListener() {
|
||||||
|
return connectionListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -15,7 +15,6 @@ import android.util.Log;
|
|||||||
|
|
||||||
public class KdeConnectBroadcastReceiver extends BroadcastReceiver {
|
public class KdeConnectBroadcastReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
|
||||||
//Log.e("KdeConnect", "Broadcast event: "+intent.getAction());
|
//Log.e("KdeConnect", "Broadcast event: "+intent.getAction());
|
||||||
@ -25,9 +24,7 @@ public class KdeConnectBroadcastReceiver extends BroadcastReceiver {
|
|||||||
switch (action) {
|
switch (action) {
|
||||||
case Intent.ACTION_MY_PACKAGE_REPLACED:
|
case Intent.ACTION_MY_PACKAGE_REPLACED:
|
||||||
Log.i("KdeConnect", "MyUpdateReceiver");
|
Log.i("KdeConnect", "MyUpdateReceiver");
|
||||||
BackgroundService.RunCommand(context, service -> {
|
BackgroundService.Start(context);
|
||||||
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
case Intent.ACTION_PACKAGE_REPLACED:
|
case Intent.ACTION_PACKAGE_REPLACED:
|
||||||
Log.i("KdeConnect", "UpdateReceiver");
|
Log.i("KdeConnect", "UpdateReceiver");
|
||||||
@ -35,27 +32,20 @@ public class KdeConnectBroadcastReceiver extends BroadcastReceiver {
|
|||||||
Log.i("KdeConnect", "Ignoring, it's not me!");
|
Log.i("KdeConnect", "Ignoring, it's not me!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
BackgroundService.RunCommand(context, service -> {
|
BackgroundService.Start(context);
|
||||||
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
case Intent.ACTION_BOOT_COMPLETED:
|
case Intent.ACTION_BOOT_COMPLETED:
|
||||||
Log.i("KdeConnect", "KdeConnectBroadcastReceiver");
|
Log.i("KdeConnect", "KdeConnectBroadcastReceiver");
|
||||||
BackgroundService.RunCommand(context, service -> {
|
BackgroundService.Start(context);
|
||||||
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
case WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION:
|
case WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION:
|
||||||
case WifiManager.WIFI_STATE_CHANGED_ACTION:
|
case WifiManager.WIFI_STATE_CHANGED_ACTION:
|
||||||
case ConnectivityManager.CONNECTIVITY_ACTION:
|
case ConnectivityManager.CONNECTIVITY_ACTION:
|
||||||
Log.i("KdeConnect", "Connection state changed, trying to connect");
|
Log.i("KdeConnect", "Connection state changed, trying to connect");
|
||||||
BackgroundService.RunCommand(context, service -> {
|
BackgroundService.ForceRefreshConnections(context);
|
||||||
service.onDeviceListChanged();
|
|
||||||
service.onNetworkChange();
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
case Intent.ACTION_SCREEN_ON:
|
case Intent.ACTION_SCREEN_ON:
|
||||||
BackgroundService.RunCommand(context, BackgroundService::onNetworkChange);
|
BackgroundService.ForceRefreshConnections(context);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Log.i("BroadcastReceiver", "Ignoring broadcast event: " + intent.getAction());
|
Log.i("BroadcastReceiver", "Ignoring broadcast event: " + intent.getAction());
|
||||||
|
@ -17,10 +17,9 @@ import android.view.View;
|
|||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect.UserInterface.MainActivity;
|
import org.kde.kdeconnect.UserInterface.MainActivity;
|
||||||
import org.kde.kdeconnect.UserInterface.PermissionsAlertDialogFragment;
|
import org.kde.kdeconnect.UserInterface.PermissionsAlertDialogFragment;
|
||||||
import org.kde.kdeconnect.UserInterface.ThemeUtil;
|
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
import org.kde.kdeconnect_tp.databinding.ActivityBigscreenBinding;
|
import org.kde.kdeconnect_tp.databinding.ActivityBigscreenBinding;
|
||||||
|
|
||||||
@ -49,7 +48,12 @@ public class BigscreenActivity extends AppCompatActivity {
|
|||||||
binding.micButton.setVisibility(View.INVISIBLE);
|
binding.micButton.setVisibility(View.INVISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
BackgroundService.RunWithPlugin(this, deviceId, BigscreenPlugin.class, plugin -> runOnUiThread(() -> {
|
BigscreenPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, BigscreenPlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
binding.leftButton.setOnClickListener(v -> plugin.sendLeft());
|
binding.leftButton.setOnClickListener(v -> plugin.sendLeft());
|
||||||
binding.rightButton.setOnClickListener(v -> plugin.sendRight());
|
binding.rightButton.setOnClickListener(v -> plugin.sendRight());
|
||||||
binding.upButton.setOnClickListener(v -> plugin.sendUp());
|
binding.upButton.setOnClickListener(v -> plugin.sendUp());
|
||||||
@ -70,7 +74,6 @@ public class BigscreenActivity extends AppCompatActivity {
|
|||||||
.create().show(getSupportFragmentManager(), null);
|
.create().show(getSupportFragmentManager(), null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void activateSTT() {
|
public void activateSTT() {
|
||||||
@ -89,9 +92,12 @@ public class BigscreenActivity extends AppCompatActivity {
|
|||||||
.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
|
.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
|
||||||
if (result.get(0) != null) {
|
if (result.get(0) != null) {
|
||||||
final String deviceId = getIntent().getStringExtra("deviceId");
|
final String deviceId = getIntent().getStringExtra("deviceId");
|
||||||
BackgroundService.RunWithPlugin(this, deviceId, BigscreenPlugin.class, plugin ->
|
BigscreenPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, BigscreenPlugin.class);
|
||||||
runOnUiThread(() -> plugin.sendSTT(result.get(0)))
|
if (plugin == null) {
|
||||||
);
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
plugin.sendSTT(result.get(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import android.content.Intent
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.service.quicksettings.TileService
|
import android.service.quicksettings.TileService
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import org.kde.kdeconnect.BackgroundService
|
import org.kde.kdeconnect.KdeConnect
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.N)
|
@RequiresApi(Build.VERSION_CODES.N)
|
||||||
class ClipboardTileService : TileService() {
|
class ClipboardTileService : TileService() {
|
||||||
@ -20,12 +20,9 @@ class ClipboardTileService : TileService() {
|
|||||||
startActivityAndCollapse(Intent(this, ClipboardFloatingActivity::class.java).apply {
|
startActivityAndCollapse(Intent(this, ClipboardFloatingActivity::class.java).apply {
|
||||||
flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
|
flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
var ids : List<String> = emptyList()
|
var ids : List<String> = emptyList()
|
||||||
val service = BackgroundService.getInstance()
|
ids = KdeConnect.getInstance().devices.values
|
||||||
if (service != null) {
|
|
||||||
ids = service.devices.values
|
|
||||||
.filter { it.isReachable && it.isPaired }
|
.filter { it.isReachable && it.isPaired }
|
||||||
.map { it.deviceId }
|
.map { it.deviceId }
|
||||||
}
|
|
||||||
putExtra("connectedDeviceIds", ArrayList(ids))
|
putExtra("connectedDeviceIds", ArrayList(ids))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,7 @@ import android.view.WindowManager;
|
|||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect.UserInterface.ThemeUtil;
|
|
||||||
import org.kde.kdeconnect_tp.databinding.ActivityFindMyPhoneBinding;
|
import org.kde.kdeconnect_tp.databinding.ActivityFindMyPhoneBinding;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -21,7 +20,7 @@ import java.util.Objects;
|
|||||||
public class FindMyPhoneActivity extends AppCompatActivity {
|
public class FindMyPhoneActivity extends AppCompatActivity {
|
||||||
static final String EXTRA_DEVICE_ID = "deviceId";
|
static final String EXTRA_DEVICE_ID = "deviceId";
|
||||||
|
|
||||||
private FindMyPhonePlugin plugin;
|
String deviceId;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
@ -39,8 +38,7 @@ public class FindMyPhoneActivity extends AppCompatActivity {
|
|||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
String deviceId = getIntent().getStringExtra(EXTRA_DEVICE_ID);
|
deviceId = getIntent().getStringExtra(EXTRA_DEVICE_ID);
|
||||||
plugin = BackgroundService.getInstance().getDevice(deviceId).getPlugin(FindMyPhonePlugin.class);
|
|
||||||
|
|
||||||
Window window = this.getWindow();
|
Window window = this.getWindow();
|
||||||
window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
|
window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
|
||||||
@ -53,11 +51,10 @@ public class FindMyPhoneActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onStart() {
|
protected void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
/*
|
FindMyPhonePlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, FindMyPhonePlugin.class);
|
||||||
For whatever reason when Android launches this activity as a SystemAlertWindow it calls:
|
if (plugin == null) {
|
||||||
onCreate(), onStart(), onResume(), onStop(), onStart(), onResume().
|
return;
|
||||||
When using BackgroundService.RunWithPlugin we get into concurrency problems and sometimes no sound will be played
|
}
|
||||||
*/
|
|
||||||
plugin.startPlaying();
|
plugin.startPlaying();
|
||||||
plugin.hideNotification();
|
plugin.hideNotification();
|
||||||
}
|
}
|
||||||
@ -65,7 +62,10 @@ public class FindMyPhoneActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onStop() {
|
protected void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
|
FindMyPhonePlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, FindMyPhonePlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
plugin.stopPlaying();
|
plugin.stopPlaying();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,8 @@ import androidx.core.content.ContextCompat;
|
|||||||
|
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
import org.kde.kdeconnect.Helpers.DeviceHelper;
|
import org.kde.kdeconnect.Helpers.DeviceHelper;
|
||||||
|
import org.kde.kdeconnect.Helpers.LifecycleHelper;
|
||||||
import org.kde.kdeconnect.Helpers.NotificationHelper;
|
import org.kde.kdeconnect.Helpers.NotificationHelper;
|
||||||
import org.kde.kdeconnect.MyApplication;
|
|
||||||
import org.kde.kdeconnect.NetworkPacket;
|
import org.kde.kdeconnect.NetworkPacket;
|
||||||
import org.kde.kdeconnect.Plugins.Plugin;
|
import org.kde.kdeconnect.Plugins.Plugin;
|
||||||
import org.kde.kdeconnect.Plugins.PluginFactory;
|
import org.kde.kdeconnect.Plugins.PluginFactory;
|
||||||
@ -107,7 +107,7 @@ public class FindMyPhonePlugin extends Plugin {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPacketReceived(NetworkPacket np) {
|
public boolean onPacketReceived(NetworkPacket np) {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || MyApplication.isInForeground()) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || LifecycleHelper.isInForeground()) {
|
||||||
Intent intent = new Intent(context, FindMyPhoneActivity.class);
|
Intent intent = new Intent(context, FindMyPhoneActivity.class);
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
intent.putExtra(FindMyPhoneActivity.EXTRA_DEVICE_ID, device.getDeviceId());
|
intent.putExtra(FindMyPhoneActivity.EXTRA_DEVICE_ID, device.getDeviceId());
|
||||||
|
@ -5,7 +5,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
|
|
||||||
public class FindMyPhoneReceiver extends BroadcastReceiver {
|
public class FindMyPhoneReceiver extends BroadcastReceiver {
|
||||||
final static String ACTION_FOUND_IT = "org.kde.kdeconnect.Plugins.FindMyPhonePlugin.foundIt";
|
final static String ACTION_FOUND_IT = "org.kde.kdeconnect.Plugins.FindMyPhonePlugin.foundIt";
|
||||||
@ -29,7 +29,10 @@ public class FindMyPhoneReceiver extends BroadcastReceiver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String deviceId = intent.getStringExtra(EXTRA_DEVICE_ID);
|
String deviceId = intent.getStringExtra(EXTRA_DEVICE_ID);
|
||||||
|
FindMyPhonePlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, FindMyPhonePlugin.class);
|
||||||
BackgroundService.RunWithPlugin(context, deviceId, FindMyPhonePlugin.class, FindMyPhonePlugin::stopPlaying);
|
if (plugin == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
plugin.stopPlaying();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.google.accompanist.themeadapter.material3.Mdc3Theme
|
import com.google.accompanist.themeadapter.material3.Mdc3Theme
|
||||||
import org.kde.kdeconnect.BackgroundService
|
import org.kde.kdeconnect.KdeConnect
|
||||||
import org.kde.kdeconnect.NetworkPacket
|
import org.kde.kdeconnect.NetworkPacket
|
||||||
import org.kde.kdeconnect.UserInterface.compose.KdeTextButton
|
import org.kde.kdeconnect.UserInterface.compose.KdeTextButton
|
||||||
import org.kde.kdeconnect.UserInterface.compose.KdeTextField
|
import org.kde.kdeconnect.UserInterface.compose.KdeTextField
|
||||||
@ -72,9 +72,12 @@ class ComposeSendActivity : AppCompatActivity() {
|
|||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e("KDE/ComposeSend", "Exception", e)
|
Log.e("KDE/ComposeSend", "Exception", e)
|
||||||
}
|
}
|
||||||
BackgroundService.RunWithPlugin(
|
val plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, MousePadPlugin::class.java)
|
||||||
this, deviceId, MousePadPlugin::class.java
|
if (plugin == null) {
|
||||||
) { plugin: MousePadPlugin -> plugin.sendKeyboardPacket(np) }
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
plugin.sendKeyboardPacket(np);
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendComposed() {
|
private fun sendComposed() {
|
||||||
|
@ -14,7 +14,7 @@ import android.view.View;
|
|||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.view.inputmethod.InputConnection;
|
import android.view.inputmethod.InputConnection;
|
||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect.NetworkPacket;
|
import org.kde.kdeconnect.NetworkPacket;
|
||||||
|
|
||||||
public class KeyListenerView extends View {
|
public class KeyListenerView extends View {
|
||||||
@ -89,7 +89,11 @@ public class KeyListenerView extends View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void sendKeyPressPacket(final NetworkPacket np) {
|
private void sendKeyPressPacket(final NetworkPacket np) {
|
||||||
BackgroundService.RunWithPlugin(getContext(), deviceId, MousePadPlugin.class, plugin -> plugin.sendKeyboardPacket(np));
|
MousePadPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, MousePadPlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
plugin.sendKeyboardPacket(np);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -22,10 +22,12 @@ import android.view.MotionEvent;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
|
||||||
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect.UserInterface.PluginSettingsActivity;
|
import org.kde.kdeconnect.UserInterface.PluginSettingsActivity;
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
|
|
||||||
@ -115,7 +117,12 @@ public class MousePadActivity
|
|||||||
final float nX = X;
|
final float nX = X;
|
||||||
final float nY = Y;
|
final float nY = Y;
|
||||||
|
|
||||||
BackgroundService.RunWithPlugin(this, deviceId, MousePadPlugin.class, plugin -> plugin.sendMouseDelta(nX, nY));
|
MousePadPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, MousePadPlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
plugin.sendMouseDelta(nX, nY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -235,24 +242,30 @@ public class MousePadActivity
|
|||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
return true;
|
return true;
|
||||||
} else if (id == R.id.menu_show_keyboard) {
|
} else if (id == R.id.menu_show_keyboard) {
|
||||||
BackgroundService.RunWithPlugin(this, deviceId, MousePadPlugin.class, plugin -> {
|
MousePadPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, MousePadPlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
finish();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (plugin.isKeyboardEnabled()) {
|
if (plugin.isKeyboardEnabled()) {
|
||||||
showKeyboard();
|
showKeyboard();
|
||||||
} else {
|
} else {
|
||||||
Toast toast = Toast.makeText(this, R.string.mousepad_keyboard_input_not_supported, Toast.LENGTH_SHORT);
|
Toast toast = Toast.makeText(this, R.string.mousepad_keyboard_input_not_supported, Toast.LENGTH_SHORT);
|
||||||
toast.show();
|
toast.show();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
return true;
|
return true;
|
||||||
} else if (id == R.id.menu_open_compose_send) {
|
} else if (id == R.id.menu_open_compose_send) {
|
||||||
BackgroundService.RunWithPlugin(this, deviceId, MousePadPlugin.class, plugin -> {
|
MousePadPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, MousePadPlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
finish();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (plugin.isKeyboardEnabled()) {
|
if (plugin.isKeyboardEnabled()) {
|
||||||
showCompose();
|
showCompose();
|
||||||
} else {
|
} else {
|
||||||
Toast toast = Toast.makeText(this, R.string.mousepad_keyboard_input_not_supported, Toast.LENGTH_SHORT);
|
Toast toast = Toast.makeText(this, R.string.mousepad_keyboard_input_not_supported, Toast.LENGTH_SHORT);
|
||||||
toast.show();
|
toast.show();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
@ -288,7 +301,12 @@ public class MousePadActivity
|
|||||||
mCurrentX = event.getX();
|
mCurrentX = event.getX();
|
||||||
mCurrentY = event.getY();
|
mCurrentY = event.getY();
|
||||||
|
|
||||||
BackgroundService.RunWithPlugin(this, deviceId, MousePadPlugin.class, plugin -> {
|
MousePadPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, MousePadPlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
finish();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
float deltaX = (mCurrentX - mPrevX) * displayDpiMultiplier * mCurrentSensitivity;
|
float deltaX = (mCurrentX - mPrevX) * displayDpiMultiplier * mCurrentSensitivity;
|
||||||
float deltaY = (mCurrentY - mPrevY) * displayDpiMultiplier * mCurrentSensitivity;
|
float deltaY = (mCurrentY - mPrevY) * displayDpiMultiplier * mCurrentSensitivity;
|
||||||
|
|
||||||
@ -300,8 +318,6 @@ public class MousePadActivity
|
|||||||
|
|
||||||
mPrevX = mCurrentX;
|
mPrevX = mCurrentX;
|
||||||
mPrevY = mCurrentY;
|
mPrevY = mCurrentY;
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -361,7 +377,12 @@ public class MousePadActivity
|
|||||||
@Override
|
@Override
|
||||||
public void onLongPress(MotionEvent e) {
|
public void onLongPress(MotionEvent e) {
|
||||||
getWindow().getDecorView().performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
|
getWindow().getDecorView().performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
|
||||||
BackgroundService.RunWithPlugin(this, deviceId, MousePadPlugin.class, MousePadPlugin::sendSingleHold);
|
MousePadPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, MousePadPlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
plugin.sendSingleHold();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -388,7 +409,12 @@ public class MousePadActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onDoubleTap(MotionEvent e) {
|
public boolean onDoubleTap(MotionEvent e) {
|
||||||
BackgroundService.RunWithPlugin(this, deviceId, MousePadPlugin.class, MousePadPlugin::sendDoubleClick);
|
MousePadPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, MousePadPlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
finish();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
plugin.sendDoubleClick();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,19 +464,39 @@ public class MousePadActivity
|
|||||||
|
|
||||||
|
|
||||||
private void sendLeftClick() {
|
private void sendLeftClick() {
|
||||||
BackgroundService.RunWithPlugin(this, deviceId, MousePadPlugin.class, MousePadPlugin::sendLeftClick);
|
MousePadPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, MousePadPlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
plugin.sendLeftClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendMiddleClick() {
|
private void sendMiddleClick() {
|
||||||
BackgroundService.RunWithPlugin(this, deviceId, MousePadPlugin.class, MousePadPlugin::sendMiddleClick);
|
MousePadPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, MousePadPlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
plugin.sendMiddleClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendRightClick() {
|
private void sendRightClick() {
|
||||||
BackgroundService.RunWithPlugin(this, deviceId, MousePadPlugin.class, MousePadPlugin::sendRightClick);
|
MousePadPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, MousePadPlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
plugin.sendRightClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendScroll(final float y) {
|
private void sendScroll(final float y) {
|
||||||
BackgroundService.RunWithPlugin(this, deviceId, MousePadPlugin.class, plugin -> plugin.sendScroll(0, y));
|
MousePadPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, MousePadPlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
plugin.sendScroll(0, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showKeyboard() {
|
private void showKeyboard() {
|
||||||
|
@ -19,11 +19,11 @@ import androidx.appcompat.app.AppCompatActivity;
|
|||||||
import org.kde.kdeconnect.BackgroundService;
|
import org.kde.kdeconnect.BackgroundService;
|
||||||
import org.kde.kdeconnect.Device;
|
import org.kde.kdeconnect.Device;
|
||||||
import org.kde.kdeconnect.Helpers.SafeTextChecker;
|
import org.kde.kdeconnect.Helpers.SafeTextChecker;
|
||||||
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect.NetworkPacket;
|
import org.kde.kdeconnect.NetworkPacket;
|
||||||
import org.kde.kdeconnect.UserInterface.List.EntryItemWithIcon;
|
import org.kde.kdeconnect.UserInterface.List.EntryItemWithIcon;
|
||||||
import org.kde.kdeconnect.UserInterface.List.ListAdapter;
|
import org.kde.kdeconnect.UserInterface.List.ListAdapter;
|
||||||
import org.kde.kdeconnect.UserInterface.List.SectionItem;
|
import org.kde.kdeconnect.UserInterface.List.SectionItem;
|
||||||
import org.kde.kdeconnect.UserInterface.ThemeUtil;
|
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
import org.kde.kdeconnect_tp.databinding.ActivitySendkeystrokesBinding;
|
import org.kde.kdeconnect_tp.databinding.ActivitySendkeystrokesBinding;
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ public class SendKeystrokesToHostActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
// If we trust the sending app, check if there is only one device paired / reachable...
|
// If we trust the sending app, check if there is only one device paired / reachable...
|
||||||
if (contentIsOkay) {
|
if (contentIsOkay) {
|
||||||
List<Device> reachableDevices = BackgroundService.getInstance().getDevices().values().stream()
|
List<Device> reachableDevices = KdeConnect.getInstance().getDevices().values().stream()
|
||||||
.filter(Device::isReachable)
|
.filter(Device::isReachable)
|
||||||
.limit(2) // we only need the first two; if its more than one, we need to show the user the device-selection
|
.limit(2) // we only need the first two; if its more than one, we need to show the user the device-selection
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
@ -103,16 +103,9 @@ public class SendKeystrokesToHostActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KdeConnect.getInstance().addDeviceListChangedCallback("SendKeystrokesToHostActivity", () -> runOnUiThread(this::updateDeviceList));
|
||||||
// subscribe to new connected devices
|
BackgroundService.ForceRefreshConnections(this); // force a network re-discover
|
||||||
BackgroundService.RunCommand(this, service -> {
|
|
||||||
service.onNetworkChange();
|
|
||||||
service.addDeviceListChangedCallback("SendKeystrokesToHostActivity", unused -> updateDeviceList());
|
|
||||||
});
|
|
||||||
|
|
||||||
// list all currently connected devices
|
|
||||||
updateDeviceList();
|
updateDeviceList();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(getApplicationContext(), R.string.sendkeystrokes_wrong_data, Toast.LENGTH_LONG).show();
|
Toast.makeText(getApplicationContext(), R.string.sendkeystrokes_wrong_data, Toast.LENGTH_LONG).show();
|
||||||
finish();
|
finish();
|
||||||
@ -122,7 +115,7 @@ public class SendKeystrokesToHostActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStop() {
|
protected void onStop() {
|
||||||
BackgroundService.RunCommand(this, service -> service.removeDeviceListChangedCallback("SendKeystrokesToHostActivity"));
|
KdeConnect.getInstance().removeDeviceListChangedCallback("SendKeystrokesToHostActivity");
|
||||||
super.onStop();
|
super.onStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +124,12 @@ public class SendKeystrokesToHostActivity extends AppCompatActivity {
|
|||||||
if (binding.textToSend.getText() != null && (toSend = binding.textToSend.getText().toString().trim()).length() > 0) {
|
if (binding.textToSend.getText() != null && (toSend = binding.textToSend.getText().toString().trim()).length() > 0) {
|
||||||
final NetworkPacket np = new NetworkPacket(MousePadPlugin.PACKET_TYPE_MOUSEPAD_REQUEST);
|
final NetworkPacket np = new NetworkPacket(MousePadPlugin.PACKET_TYPE_MOUSEPAD_REQUEST);
|
||||||
np.set("key", toSend);
|
np.set("key", toSend);
|
||||||
BackgroundService.RunWithPlugin(this, deviceId.getDeviceId(), MousePadPlugin.class, plugin -> plugin.sendKeyboardPacket(np));
|
MousePadPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId.getDeviceId(), MousePadPlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
plugin.sendKeyboardPacket(np);
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
getApplicationContext(),
|
getApplicationContext(),
|
||||||
getString(R.string.sendkeystrokes_sent_text, toSend, deviceId.getName()),
|
getString(R.string.sendkeystrokes_sent_text, toSend, deviceId.getName()),
|
||||||
@ -143,9 +141,7 @@ public class SendKeystrokesToHostActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
|
|
||||||
private void updateDeviceList() {
|
private void updateDeviceList() {
|
||||||
BackgroundService.RunCommand(this, service -> {
|
Collection<Device> devices = KdeConnect.getInstance().getDevices().values();
|
||||||
|
|
||||||
Collection<Device> devices = service.getDevices().values();
|
|
||||||
final ArrayList<Device> devicesList = new ArrayList<>();
|
final ArrayList<Device> devicesList = new ArrayList<>();
|
||||||
final ArrayList<ListAdapter.Item> items = new ArrayList<>();
|
final ArrayList<ListAdapter.Item> items = new ArrayList<>();
|
||||||
|
|
||||||
@ -159,14 +155,13 @@ public class SendKeystrokesToHostActivity extends AppCompatActivity {
|
|||||||
section.isEmpty = false;
|
section.isEmpty = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
runOnUiThread(() -> {
|
|
||||||
binding.devicesList.setAdapter(new ListAdapter(SendKeystrokesToHostActivity.this, items));
|
binding.devicesList.setAdapter(new ListAdapter(SendKeystrokesToHostActivity.this, items));
|
||||||
binding.devicesList.setOnItemClickListener((adapterView, view, i, l) -> {
|
binding.devicesList.setOnItemClickListener((adapterView, view, i, l) -> {
|
||||||
Device device = devicesList.get(i - 1); // NOTE: -1 because of the title!
|
Device device = devicesList.get(i - 1); // NOTE: -1 because of the title!
|
||||||
sendKeys(device);
|
sendKeys(device);
|
||||||
this.finish(); // close the activity
|
this.finish(); // close the activity
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// only one device is connected and we trust the text to send -> send it and close the activity.
|
// only one device is connected and we trust the text to send -> send it and close the activity.
|
||||||
// Usually we already check it in `onStart` - but if the BackgroundService was not started/connected to the host
|
// Usually we already check it in `onStart` - but if the BackgroundService was not started/connected to the host
|
||||||
@ -177,7 +172,6 @@ public class SendKeystrokesToHostActivity extends AppCompatActivity {
|
|||||||
sendKeys(device);
|
sendKeys(device);
|
||||||
this.finish(); // close the activity
|
this.finish(); // close the activity
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,8 +11,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.support.v4.media.session.MediaSessionCompat;
|
import android.support.v4.media.session.MediaSessionCompat;
|
||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect.Device;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the mpris media notification's buttons are pressed
|
* Called when the mpris media notification's buttons are pressed
|
||||||
@ -29,7 +28,7 @@ public class MprisMediaNotificationReceiver extends BroadcastReceiver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
//First case: buttons send by other applications via the media session APIs
|
//First case: buttons send by other applications via the media session APIs. They don't target a specific device.
|
||||||
if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
|
if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
|
||||||
//Route these buttons to the media session, which will handle them
|
//Route these buttons to the media session, which will handle them
|
||||||
MediaSessionCompat mediaSession = MprisMediaSession.getMediaSession();
|
MediaSessionCompat mediaSession = MprisMediaSession.getMediaSession();
|
||||||
@ -39,13 +38,10 @@ public class MprisMediaNotificationReceiver extends BroadcastReceiver {
|
|||||||
//Second case: buttons on the notification, which we created ourselves
|
//Second case: buttons on the notification, which we created ourselves
|
||||||
|
|
||||||
//Get the correct device, the mpris plugin and the mpris player
|
//Get the correct device, the mpris plugin and the mpris player
|
||||||
BackgroundService service = BackgroundService.getInstance();
|
String deviceId = intent.getStringExtra(EXTRA_DEVICE_ID);
|
||||||
if (service == null) return;
|
MprisPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, MprisPlugin.class);
|
||||||
Device device = service.getDevice(intent.getStringExtra(EXTRA_DEVICE_ID));
|
if (plugin == null) return;
|
||||||
if (device == null) return;
|
MprisPlugin.MprisPlayer player = plugin.getPlayerStatus(intent.getStringExtra(EXTRA_MPRIS_PLAYER));
|
||||||
MprisPlugin mpris = device.getPlugin(MprisPlugin.class);
|
|
||||||
if (mpris == null) return;
|
|
||||||
MprisPlugin.MprisPlayer player = mpris.getPlayerStatus(intent.getStringExtra(EXTRA_MPRIS_PLAYER));
|
|
||||||
if (player == null) return;
|
if (player == null) return;
|
||||||
|
|
||||||
//Forward the action to the player
|
//Forward the action to the player
|
||||||
@ -65,7 +61,9 @@ public class MprisMediaNotificationReceiver extends BroadcastReceiver {
|
|||||||
case ACTION_CLOSE_NOTIFICATION:
|
case ACTION_CLOSE_NOTIFICATION:
|
||||||
//The user dismissed the notification: actually handle its removal correctly
|
//The user dismissed the notification: actually handle its removal correctly
|
||||||
MprisMediaSession.getInstance().closeMediaNotification();
|
MprisMediaSession.getInstance().closeMediaNotification();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ import android.content.SharedPreferences;
|
|||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.os.Handler;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.service.notification.StatusBarNotification;
|
import android.service.notification.StatusBarNotification;
|
||||||
import android.support.v4.media.MediaMetadataCompat;
|
import android.support.v4.media.MediaMetadataCompat;
|
||||||
@ -27,9 +28,9 @@ import androidx.core.app.TaskStackBuilder;
|
|||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.media.app.NotificationCompat.MediaStyle;
|
import androidx.media.app.NotificationCompat.MediaStyle;
|
||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
|
||||||
import org.kde.kdeconnect.Device;
|
import org.kde.kdeconnect.Device;
|
||||||
import org.kde.kdeconnect.Helpers.NotificationHelper;
|
import org.kde.kdeconnect.Helpers.NotificationHelper;
|
||||||
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect.Plugins.NotificationsPlugin.NotificationReceiver;
|
import org.kde.kdeconnect.Plugins.NotificationsPlugin.NotificationReceiver;
|
||||||
import org.kde.kdeconnect.Plugins.SystemVolumePlugin.SystemVolumePlugin;
|
import org.kde.kdeconnect.Plugins.SystemVolumePlugin.SystemVolumePlugin;
|
||||||
import org.kde.kdeconnect.Plugins.SystemVolumePlugin.SystemVolumeProvider;
|
import org.kde.kdeconnect.Plugins.SystemVolumePlugin.SystemVolumeProvider;
|
||||||
@ -112,20 +113,20 @@ public class MprisMediaSession implements
|
|||||||
* <p>
|
* <p>
|
||||||
* Can be called multiple times, once for each device
|
* Can be called multiple times, once for each device
|
||||||
*
|
*
|
||||||
* @param _context The context
|
* @param context The context
|
||||||
* @param mpris The mpris plugin
|
* @param plugin The mpris plugin
|
||||||
* @param device The device id
|
* @param device The device id
|
||||||
*/
|
*/
|
||||||
public void onCreate(Context _context, MprisPlugin mpris, String device) {
|
public void onCreate(Context context, MprisPlugin plugin, String device) {
|
||||||
if (mprisDevices.isEmpty()) {
|
if (mprisDevices.isEmpty()) {
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(_context);
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
prefs.registerOnSharedPreferenceChangeListener(this);
|
prefs.registerOnSharedPreferenceChangeListener(this);
|
||||||
}
|
}
|
||||||
context = _context;
|
this.context = context;
|
||||||
mprisDevices.add(device);
|
mprisDevices.add(device);
|
||||||
|
|
||||||
mpris.setPlayerListUpdatedHandler("media_notification", this::updateMediaNotification);
|
plugin.setPlayerListUpdatedHandler("media_notification", this::updateMediaNotification);
|
||||||
mpris.setPlayerStatusUpdatedHandler("media_notification", this::updateMediaNotification);
|
plugin.setPlayerStatusUpdatedHandler("media_notification", this::updateMediaNotification);
|
||||||
|
|
||||||
NotificationReceiver.RunCommand(context, service -> {
|
NotificationReceiver.RunCommand(context, service -> {
|
||||||
|
|
||||||
@ -137,8 +138,6 @@ public class MprisMediaSession implements
|
|||||||
onListenerConnected(service);
|
onListenerConnected(service);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
updateMediaNotification();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -146,13 +145,13 @@ public class MprisMediaSession implements
|
|||||||
* <p>
|
* <p>
|
||||||
* Can be called multiple times, once for each device
|
* Can be called multiple times, once for each device
|
||||||
*
|
*
|
||||||
* @param mpris The mpris plugin
|
* @param plugin The mpris plugin
|
||||||
* @param device The device id
|
* @param device The device id
|
||||||
*/
|
*/
|
||||||
public void onDestroy(MprisPlugin mpris, String device) {
|
public void onDestroy(MprisPlugin plugin, String device) {
|
||||||
mprisDevices.remove(device);
|
mprisDevices.remove(device);
|
||||||
mpris.removePlayerStatusUpdatedHandler("media_notification");
|
plugin.removePlayerStatusUpdatedHandler("media_notification");
|
||||||
mpris.removePlayerListUpdatedHandler("media_notification");
|
plugin.removePlayerListUpdatedHandler("media_notification");
|
||||||
updateMediaNotification();
|
updateMediaNotification();
|
||||||
|
|
||||||
if (mprisDevices.isEmpty()) {
|
if (mprisDevices.isEmpty()) {
|
||||||
@ -166,21 +165,19 @@ public class MprisMediaSession implements
|
|||||||
* <p>
|
* <p>
|
||||||
* Prefers playing devices/mpris players, but tries to keep displaying the same
|
* Prefers playing devices/mpris players, but tries to keep displaying the same
|
||||||
* player and device, while possible.
|
* player and device, while possible.
|
||||||
*
|
|
||||||
* @param service The background service
|
|
||||||
*/
|
*/
|
||||||
private void updateCurrentPlayer(BackgroundService service) {
|
private void updateCurrentPlayer() {
|
||||||
Pair<Device, MprisPlugin.MprisPlayer> player = findPlayer(service);
|
Pair<Device, MprisPlugin.MprisPlayer> player = findPlayer();
|
||||||
|
|
||||||
//Update the last-displayed device and player
|
//Update the last-displayed device and player
|
||||||
notificationDevice = player.first == null ? null : player.first.getDeviceId();
|
notificationDevice = player.first == null ? null : player.first.getDeviceId();
|
||||||
notificationPlayer = player.second;
|
notificationPlayer = player.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pair<Device, MprisPlugin.MprisPlayer> findPlayer(BackgroundService service) {
|
private Pair<Device, MprisPlugin.MprisPlayer> findPlayer() {
|
||||||
//First try the previously displayed player (if still playing) or the previous displayed device (otherwise)
|
//First try the previously displayed player (if still playing) or the previous displayed device (otherwise)
|
||||||
if (notificationDevice != null && mprisDevices.contains(notificationDevice)) {
|
if (notificationDevice != null && mprisDevices.contains(notificationDevice)) {
|
||||||
Device device = service.getDevice(notificationDevice);
|
Device device = KdeConnect.getInstance().getDevice(notificationDevice);
|
||||||
|
|
||||||
MprisPlugin.MprisPlayer player;
|
MprisPlugin.MprisPlayer player;
|
||||||
if (notificationPlayer != null && notificationPlayer.isPlaying()) {
|
if (notificationPlayer != null && notificationPlayer.isPlaying()) {
|
||||||
@ -194,7 +191,7 @@ public class MprisMediaSession implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try a different player from another device
|
// Try a different player from another device
|
||||||
for (Device otherDevice : service.getDevices().values()) {
|
for (Device otherDevice : KdeConnect.getInstance().getDevices().values()) {
|
||||||
MprisPlugin.MprisPlayer player = getPlayerFromDevice(otherDevice, null);
|
MprisPlugin.MprisPlayer player = getPlayerFromDevice(otherDevice, null);
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
return new Pair<>(otherDevice, player);
|
return new Pair<>(otherDevice, player);
|
||||||
@ -205,7 +202,7 @@ public class MprisMediaSession implements
|
|||||||
// This will succeed if it's paused:
|
// This will succeed if it's paused:
|
||||||
// that allows pausing and subsequently resuming via the notification
|
// that allows pausing and subsequently resuming via the notification
|
||||||
if (notificationDevice != null && mprisDevices.contains(notificationDevice)) {
|
if (notificationDevice != null && mprisDevices.contains(notificationDevice)) {
|
||||||
Device device = service.getDevice(notificationDevice);
|
Device device = KdeConnect.getInstance().getDevice(notificationDevice);
|
||||||
|
|
||||||
MprisPlugin.MprisPlayer player = getPlayerFromDevice(device, notificationPlayer);
|
MprisPlugin.MprisPlayer player = getPlayerFromDevice(device, notificationPlayer);
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
@ -244,19 +241,20 @@ public class MprisMediaSession implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateRemoteDeviceVolumeControl() {
|
private void updateRemoteDeviceVolumeControl() {
|
||||||
// Volume control feature is only available from Lollipop onwards
|
SystemVolumePlugin plugin = KdeConnect.getInstance().getDevicePlugin(notificationDevice, SystemVolumePlugin.class);
|
||||||
BackgroundService.RunWithPlugin(context, notificationDevice, SystemVolumePlugin.class, plugin -> {
|
if (plugin == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
SystemVolumeProvider systemVolumeProvider = SystemVolumeProvider.fromPlugin(plugin);
|
SystemVolumeProvider systemVolumeProvider = SystemVolumeProvider.fromPlugin(plugin);
|
||||||
systemVolumeProvider.addStateListener(this);
|
systemVolumeProvider.addStateListener(this);
|
||||||
systemVolumeProvider.startTrackingVolumeKeys();
|
systemVolumeProvider.startTrackingVolumeKeys();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the media control notification
|
* Update the media control notification
|
||||||
*/
|
*/
|
||||||
private void updateMediaNotification() {
|
private void updateMediaNotification() {
|
||||||
BackgroundService.RunCommand(context, service -> {
|
|
||||||
//If the user disabled the media notification, do not show it
|
//If the user disabled the media notification, do not show it
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
if (!prefs.getBoolean(context.getString(R.string.mpris_notification_key), true)) {
|
if (!prefs.getBoolean(context.getString(R.string.mpris_notification_key), true)) {
|
||||||
@ -264,8 +262,15 @@ public class MprisMediaSession implements
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mediaSession == null) {
|
||||||
|
mediaSession = new MediaSessionCompat(context, MPRIS_MEDIA_SESSION_TAG);
|
||||||
|
mediaSession.setCallback(mediaSessionCallback, new Handler(context.getMainLooper()));
|
||||||
|
// Deprecated flags not required in Build.VERSION_CODES.O and later
|
||||||
|
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
|
||||||
|
}
|
||||||
|
|
||||||
//Make sure our information is up-to-date
|
//Make sure our information is up-to-date
|
||||||
updateCurrentPlayer(service);
|
updateCurrentPlayer();
|
||||||
|
|
||||||
//If the player disappeared (and no other playing one found), just remove the notification
|
//If the player disappeared (and no other playing one found), just remove the notification
|
||||||
if (notificationPlayer == null) {
|
if (notificationPlayer == null) {
|
||||||
@ -273,14 +278,6 @@ public class MprisMediaSession implements
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Update the metadata and playback status
|
|
||||||
if (mediaSession == null) {
|
|
||||||
mediaSession = new MediaSessionCompat(context, MPRIS_MEDIA_SESSION_TAG);
|
|
||||||
mediaSession.setCallback(mediaSessionCallback);
|
|
||||||
// Deprecated flags not required in Build.VERSION_CODES.O and later
|
|
||||||
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateRemoteDeviceVolumeControl();
|
updateRemoteDeviceVolumeControl();
|
||||||
|
|
||||||
MediaMetadataCompat.Builder metadata = new MediaMetadataCompat.Builder();
|
MediaMetadataCompat.Builder metadata = new MediaMetadataCompat.Builder();
|
||||||
@ -317,41 +314,41 @@ public class MprisMediaSession implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Create all actions (previous/play/pause/next)
|
//Create all actions (previous/play/pause/next)
|
||||||
Intent iPlay = new Intent(service, MprisMediaNotificationReceiver.class);
|
Intent iPlay = new Intent(context, MprisMediaNotificationReceiver.class);
|
||||||
iPlay.setAction(MprisMediaNotificationReceiver.ACTION_PLAY);
|
iPlay.setAction(MprisMediaNotificationReceiver.ACTION_PLAY);
|
||||||
iPlay.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
|
iPlay.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
|
||||||
iPlay.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayer());
|
iPlay.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayerName());
|
||||||
PendingIntent piPlay = PendingIntent.getBroadcast(service, 0, iPlay, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
PendingIntent piPlay = PendingIntent.getBroadcast(context, 0, iPlay, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
||||||
NotificationCompat.Action.Builder aPlay = new NotificationCompat.Action.Builder(
|
NotificationCompat.Action.Builder aPlay = new NotificationCompat.Action.Builder(
|
||||||
R.drawable.ic_play_white, service.getString(R.string.mpris_play), piPlay);
|
R.drawable.ic_play_white, context.getString(R.string.mpris_play), piPlay);
|
||||||
|
|
||||||
Intent iPause = new Intent(service, MprisMediaNotificationReceiver.class);
|
Intent iPause = new Intent(context, MprisMediaNotificationReceiver.class);
|
||||||
iPause.setAction(MprisMediaNotificationReceiver.ACTION_PAUSE);
|
iPause.setAction(MprisMediaNotificationReceiver.ACTION_PAUSE);
|
||||||
iPause.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
|
iPause.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
|
||||||
iPause.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayer());
|
iPause.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayerName());
|
||||||
PendingIntent piPause = PendingIntent.getBroadcast(service, 0, iPause, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
PendingIntent piPause = PendingIntent.getBroadcast(context, 0, iPause, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
||||||
NotificationCompat.Action.Builder aPause = new NotificationCompat.Action.Builder(
|
NotificationCompat.Action.Builder aPause = new NotificationCompat.Action.Builder(
|
||||||
R.drawable.ic_pause_white, service.getString(R.string.mpris_pause), piPause);
|
R.drawable.ic_pause_white, context.getString(R.string.mpris_pause), piPause);
|
||||||
|
|
||||||
Intent iPrevious = new Intent(service, MprisMediaNotificationReceiver.class);
|
Intent iPrevious = new Intent(context, MprisMediaNotificationReceiver.class);
|
||||||
iPrevious.setAction(MprisMediaNotificationReceiver.ACTION_PREVIOUS);
|
iPrevious.setAction(MprisMediaNotificationReceiver.ACTION_PREVIOUS);
|
||||||
iPrevious.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
|
iPrevious.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
|
||||||
iPrevious.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayer());
|
iPrevious.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayerName());
|
||||||
PendingIntent piPrevious = PendingIntent.getBroadcast(service, 0, iPrevious, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
PendingIntent piPrevious = PendingIntent.getBroadcast(context, 0, iPrevious, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
||||||
NotificationCompat.Action.Builder aPrevious = new NotificationCompat.Action.Builder(
|
NotificationCompat.Action.Builder aPrevious = new NotificationCompat.Action.Builder(
|
||||||
R.drawable.ic_previous_white, service.getString(R.string.mpris_previous), piPrevious);
|
R.drawable.ic_previous_white, context.getString(R.string.mpris_previous), piPrevious);
|
||||||
|
|
||||||
Intent iNext = new Intent(service, MprisMediaNotificationReceiver.class);
|
Intent iNext = new Intent(context, MprisMediaNotificationReceiver.class);
|
||||||
iNext.setAction(MprisMediaNotificationReceiver.ACTION_NEXT);
|
iNext.setAction(MprisMediaNotificationReceiver.ACTION_NEXT);
|
||||||
iNext.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
|
iNext.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
|
||||||
iNext.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayer());
|
iNext.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayerName());
|
||||||
PendingIntent piNext = PendingIntent.getBroadcast(service, 0, iNext, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
PendingIntent piNext = PendingIntent.getBroadcast(context, 0, iNext, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
||||||
NotificationCompat.Action.Builder aNext = new NotificationCompat.Action.Builder(
|
NotificationCompat.Action.Builder aNext = new NotificationCompat.Action.Builder(
|
||||||
R.drawable.ic_next_white, service.getString(R.string.mpris_next), piNext);
|
R.drawable.ic_next_white, context.getString(R.string.mpris_next), piNext);
|
||||||
|
|
||||||
Intent iOpenActivity = new Intent(service, MprisActivity.class);
|
Intent iOpenActivity = new Intent(context, MprisActivity.class);
|
||||||
iOpenActivity.putExtra("deviceId", notificationDevice);
|
iOpenActivity.putExtra("deviceId", notificationDevice);
|
||||||
iOpenActivity.putExtra("player", notificationPlayer.getPlayer());
|
iOpenActivity.putExtra("player", notificationPlayer.getPlayerName());
|
||||||
|
|
||||||
PendingIntent piOpenActivity = TaskStackBuilder.create(context)
|
PendingIntent piOpenActivity = TaskStackBuilder.create(context)
|
||||||
.addNextIntentWithParentStack(iOpenActivity)
|
.addNextIntentWithParentStack(iOpenActivity)
|
||||||
@ -364,9 +361,9 @@ public class MprisMediaSession implements
|
|||||||
.setContentIntent(piOpenActivity)
|
.setContentIntent(piOpenActivity)
|
||||||
.setSmallIcon(R.drawable.ic_play_white)
|
.setSmallIcon(R.drawable.ic_play_white)
|
||||||
.setShowWhen(false)
|
.setShowWhen(false)
|
||||||
.setColor(ContextCompat.getColor(service, R.color.primary))
|
.setColor(ContextCompat.getColor(context, R.color.primary))
|
||||||
.setVisibility(androidx.core.app.NotificationCompat.VISIBILITY_PUBLIC)
|
.setVisibility(androidx.core.app.NotificationCompat.VISIBILITY_PUBLIC)
|
||||||
.setSubText(service.getDevice(notificationDevice).getName());
|
.setSubText(KdeConnect.getInstance().getDevice(notificationDevice).getName());
|
||||||
|
|
||||||
if (!notificationPlayer.getTitle().isEmpty()) {
|
if (!notificationPlayer.getTitle().isEmpty()) {
|
||||||
notification.setContentTitle(notificationPlayer.getTitle());
|
notification.setContentTitle(notificationPlayer.getTitle());
|
||||||
@ -375,13 +372,13 @@ public class MprisMediaSession implements
|
|||||||
}
|
}
|
||||||
//Only set the notification body text if we have an author and/or album
|
//Only set the notification body text if we have an author and/or album
|
||||||
if (!notificationPlayer.getArtist().isEmpty() && !notificationPlayer.getAlbum().isEmpty()) {
|
if (!notificationPlayer.getArtist().isEmpty() && !notificationPlayer.getAlbum().isEmpty()) {
|
||||||
notification.setContentText(notificationPlayer.getArtist() + " - " + notificationPlayer.getAlbum() + " (" + notificationPlayer.getPlayer() + ")");
|
notification.setContentText(notificationPlayer.getArtist() + " - " + notificationPlayer.getAlbum() + " (" + notificationPlayer.getPlayerName() + ")");
|
||||||
} else if (!notificationPlayer.getArtist().isEmpty()) {
|
} else if (!notificationPlayer.getArtist().isEmpty()) {
|
||||||
notification.setContentText(notificationPlayer.getArtist() + " (" + notificationPlayer.getPlayer() + ")");
|
notification.setContentText(notificationPlayer.getArtist() + " (" + notificationPlayer.getPlayerName() + ")");
|
||||||
} else if (!notificationPlayer.getAlbum().isEmpty()) {
|
} else if (!notificationPlayer.getAlbum().isEmpty()) {
|
||||||
notification.setContentText(notificationPlayer.getAlbum() + " (" + notificationPlayer.getPlayer() + ")");
|
notification.setContentText(notificationPlayer.getAlbum() + " (" + notificationPlayer.getPlayerName() + ")");
|
||||||
} else {
|
} else {
|
||||||
notification.setContentText(notificationPlayer.getPlayer());
|
notification.setContentText(notificationPlayer.getPlayerName());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (albumArt != null) {
|
if (albumArt != null) {
|
||||||
@ -389,11 +386,11 @@ public class MprisMediaSession implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!notificationPlayer.isPlaying()) {
|
if (!notificationPlayer.isPlaying()) {
|
||||||
Intent iCloseNotification = new Intent(service, MprisMediaNotificationReceiver.class);
|
Intent iCloseNotification = new Intent(context, MprisMediaNotificationReceiver.class);
|
||||||
iCloseNotification.setAction(MprisMediaNotificationReceiver.ACTION_CLOSE_NOTIFICATION);
|
iCloseNotification.setAction(MprisMediaNotificationReceiver.ACTION_CLOSE_NOTIFICATION);
|
||||||
iCloseNotification.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
|
iCloseNotification.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
|
||||||
iCloseNotification.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayer());
|
iCloseNotification.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayerName());
|
||||||
PendingIntent piCloseNotification = PendingIntent.getBroadcast(service, 0, iCloseNotification, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
PendingIntent piCloseNotification = PendingIntent.getBroadcast(context, 0, iCloseNotification, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
||||||
notification.setDeleteIntent(piCloseNotification);
|
notification.setDeleteIntent(piCloseNotification);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,7 +446,6 @@ public class MprisMediaSession implements
|
|||||||
mediaSession.setActive(true);
|
mediaSession.setActive(true);
|
||||||
final NotificationManager nm = ContextCompat.getSystemService(context, NotificationManager.class);
|
final NotificationManager nm = ContextCompat.getSystemService(context, NotificationManager.class);
|
||||||
nm.notify(MPRIS_MEDIA_NOTIFICATION_ID, notification.build());
|
nm.notify(MPRIS_MEDIA_NOTIFICATION_ID, notification.build());
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void closeMediaNotification() {
|
public void closeMediaNotification() {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package org.kde.kdeconnect.Plugins.MprisPlugin;
|
package org.kde.kdeconnect.Plugins.MprisPlugin;
|
||||||
|
|
||||||
import android.content.ActivityNotFoundException;
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
@ -10,7 +9,6 @@ import android.net.Uri;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
@ -28,12 +26,9 @@ import androidx.core.graphics.drawable.DrawableCompat;
|
|||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
import org.kde.kdeconnect.Backends.BaseLink;
|
|
||||||
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
|
||||||
import org.kde.kdeconnect.Helpers.VideoUrlsHelper;
|
import org.kde.kdeconnect.Helpers.VideoUrlsHelper;
|
||||||
import org.kde.kdeconnect.Helpers.VolumeHelperKt;
|
import org.kde.kdeconnect.Helpers.VolumeHelperKt;
|
||||||
import org.kde.kdeconnect.NetworkPacket;
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
import org.kde.kdeconnect_tp.databinding.MprisControlBinding;
|
import org.kde.kdeconnect_tp.databinding.MprisControlBinding;
|
||||||
import org.kde.kdeconnect_tp.databinding.MprisNowPlayingBinding;
|
import org.kde.kdeconnect_tp.databinding.MprisNowPlayingBinding;
|
||||||
@ -49,18 +44,9 @@ public class MprisNowPlayingFragment extends Fragment implements VolumeKeyListen
|
|||||||
private MprisNowPlayingBinding activityMprisBinding;
|
private MprisNowPlayingBinding activityMprisBinding;
|
||||||
private String deviceId;
|
private String deviceId;
|
||||||
private Runnable positionSeekUpdateRunnable = null;
|
private Runnable positionSeekUpdateRunnable = null;
|
||||||
|
|
||||||
|
private String targetPlayerName = "";
|
||||||
private MprisPlugin.MprisPlayer targetPlayer = null;
|
private MprisPlugin.MprisPlayer targetPlayer = null;
|
||||||
private final BaseLinkProvider.ConnectionReceiver connectionReceiver = new BaseLinkProvider.ConnectionReceiver() {
|
|
||||||
@Override
|
|
||||||
public void onConnectionReceived(NetworkPacket identityPacket, BaseLink link) {
|
|
||||||
connectToPlugin(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConnectionLost(BaseLink link) {
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public static MprisNowPlayingFragment newInstance(String deviceId) {
|
public static MprisNowPlayingFragment newInstance(String deviceId) {
|
||||||
MprisNowPlayingFragment mprisNowPlayingFragment = new MprisNowPlayingFragment();
|
MprisNowPlayingFragment mprisNowPlayingFragment = new MprisNowPlayingFragment();
|
||||||
@ -94,32 +80,27 @@ public class MprisNowPlayingFragment extends Fragment implements VolumeKeyListen
|
|||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
|
||||||
if (activityMprisBinding == null) {
|
|
||||||
activityMprisBinding = MprisNowPlayingBinding.inflate(inflater);
|
activityMprisBinding = MprisNowPlayingBinding.inflate(inflater);
|
||||||
mprisControlBinding = activityMprisBinding.mprisControl;
|
mprisControlBinding = activityMprisBinding.mprisControl;
|
||||||
|
|
||||||
String targetPlayerName = "";
|
deviceId = requireArguments().getString(MprisPlugin.DEVICE_ID_KEY);
|
||||||
Intent activityIntent = requireActivity().getIntent();
|
|
||||||
activityIntent.getStringExtra("player");
|
|
||||||
activityIntent.removeExtra("player");
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(targetPlayerName)) {
|
targetPlayerName = "";
|
||||||
if (savedInstanceState != null) {
|
Intent activityIntent = requireActivity().getIntent();
|
||||||
|
if (activityIntent.hasExtra("player")) {
|
||||||
|
targetPlayerName = activityIntent.getStringExtra("player");
|
||||||
|
activityIntent.removeExtra("player");
|
||||||
|
} else if (savedInstanceState != null) {
|
||||||
targetPlayerName = savedInstanceState.getString("targetPlayer");
|
targetPlayerName = savedInstanceState.getString("targetPlayer");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
deviceId = requireArguments().getString(MprisPlugin.DEVICE_ID_KEY);
|
connectToPlugin();
|
||||||
|
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(requireContext());
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(requireContext());
|
||||||
String interval_time_str = prefs.getString(getString(R.string.mpris_time_key),
|
String interval_time_str = prefs.getString(getString(R.string.mpris_time_key),
|
||||||
getString(R.string.mpris_time_default));
|
getString(R.string.mpris_time_default));
|
||||||
final int interval_time = Integer.parseInt(interval_time_str);
|
final int interval_time = Integer.parseInt(interval_time_str);
|
||||||
|
|
||||||
BackgroundService.RunCommand(requireContext(), service -> service.addConnectionListener(connectionReceiver));
|
|
||||||
connectToPlugin(targetPlayerName);
|
|
||||||
|
|
||||||
performActionOnClick(mprisControlBinding.loopButton, p -> {
|
performActionOnClick(mprisControlBinding.loopButton, p -> {
|
||||||
switch (p.getLoopStatus()) {
|
switch (p.getLoopStatus()) {
|
||||||
case "None":
|
case "None":
|
||||||
@ -159,23 +140,18 @@ public class MprisNowPlayingFragment extends Fragment implements VolumeKeyListen
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStopTrackingTouch(final SeekBar seekBar) {
|
public void onStopTrackingTouch(final SeekBar seekBar) {
|
||||||
BackgroundService.RunCommand(requireContext(), service -> {
|
|
||||||
if (targetPlayer == null) return;
|
if (targetPlayer == null) return;
|
||||||
targetPlayer.setVolume(seekBar.getProgress());
|
targetPlayer.setVolume(seekBar.getProgress());
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
positionSeekUpdateRunnable = () -> {
|
positionSeekUpdateRunnable = () -> {
|
||||||
Context context = getContext();
|
if (!isAdded()) return; // Fragment was already detached
|
||||||
if (context == null) return; // Fragment was already detached
|
|
||||||
BackgroundService.RunCommand(context, service -> {
|
|
||||||
if (targetPlayer != null) {
|
if (targetPlayer != null) {
|
||||||
mprisControlBinding.positionSeek.setProgress((int) (targetPlayer.getPosition()));
|
mprisControlBinding.positionSeek.setProgress((int) (targetPlayer.getPosition()));
|
||||||
}
|
}
|
||||||
positionSeekUpdateHandler.removeCallbacks(positionSeekUpdateRunnable);
|
positionSeekUpdateHandler.removeCallbacks(positionSeekUpdateRunnable);
|
||||||
positionSeekUpdateHandler.postDelayed(positionSeekUpdateRunnable, 1000);
|
positionSeekUpdateHandler.postDelayed(positionSeekUpdateRunnable, 1000);
|
||||||
});
|
|
||||||
};
|
};
|
||||||
positionSeekUpdateHandler.postDelayed(positionSeekUpdateRunnable, 200);
|
positionSeekUpdateHandler.postDelayed(positionSeekUpdateRunnable, 200);
|
||||||
|
|
||||||
@ -192,36 +168,54 @@ public class MprisNowPlayingFragment extends Fragment implements VolumeKeyListen
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStopTrackingTouch(final SeekBar seekBar) {
|
public void onStopTrackingTouch(final SeekBar seekBar) {
|
||||||
BackgroundService.RunCommand(requireContext(), service -> {
|
|
||||||
if (targetPlayer != null) {
|
if (targetPlayer != null) {
|
||||||
targetPlayer.setPosition(seekBar.getProgress());
|
targetPlayer.setPosition(seekBar.getProgress());
|
||||||
}
|
}
|
||||||
positionSeekUpdateHandler.postDelayed(positionSeekUpdateRunnable, 200);
|
positionSeekUpdateHandler.postDelayed(positionSeekUpdateRunnable, 200);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
mprisControlBinding.nowPlayingTextview.setSelected(true);
|
mprisControlBinding.nowPlayingTextview.setSelected(true);
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return activityMprisBinding.getRoot();
|
return activityMprisBinding.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connectToPlugin(final String targetPlayerName) {
|
@Override
|
||||||
BackgroundService.RunWithPlugin(requireContext(), deviceId, MprisPlugin.class, mpris -> {
|
public void onDestroyView() {
|
||||||
targetPlayer = mpris.getPlayerStatus(targetPlayerName);
|
disconnectFromPlugin();
|
||||||
|
super.onDestroyView();
|
||||||
|
}
|
||||||
|
|
||||||
mpris.setPlayerStatusUpdatedHandler("activity", () -> requireActivity().runOnUiThread(() -> updatePlayerStatus(mpris)));
|
private void disconnectFromPlugin() {
|
||||||
mpris.setPlayerListUpdatedHandler("activity", () -> {
|
MprisPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, MprisPlugin.class);
|
||||||
final List<String> playerList = mpris.getPlayerList();
|
if (plugin != null) {
|
||||||
|
plugin.removePlayerListUpdatedHandler("activity");
|
||||||
|
plugin.removePlayerStatusUpdatedHandler("activity");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connectToPlugin() {
|
||||||
|
MprisPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, MprisPlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
if (isAdded()) {
|
||||||
|
requireActivity().finish();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
targetPlayer = plugin.getPlayerStatus(targetPlayerName);
|
||||||
|
|
||||||
|
plugin.setPlayerStatusUpdatedHandler("activity", () -> requireActivity().runOnUiThread(() -> {
|
||||||
|
updatePlayerStatus(plugin);
|
||||||
|
}));
|
||||||
|
plugin.setPlayerListUpdatedHandler("activity", () -> requireActivity().runOnUiThread(() -> {
|
||||||
|
final List<String> playerList = plugin.getPlayerList();
|
||||||
final ArrayAdapter<String> adapter = new ArrayAdapter<>(requireContext(),
|
final ArrayAdapter<String> adapter = new ArrayAdapter<>(requireContext(),
|
||||||
android.R.layout.simple_spinner_item,
|
android.R.layout.simple_spinner_item,
|
||||||
playerList.toArray(ArrayUtils.EMPTY_STRING_ARRAY)
|
playerList.toArray(ArrayUtils.EMPTY_STRING_ARRAY)
|
||||||
);
|
);
|
||||||
|
|
||||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
requireActivity().runOnUiThread(() -> {
|
|
||||||
mprisControlBinding.playerSpinner.setAdapter(adapter);
|
mprisControlBinding.playerSpinner.setAdapter(adapter);
|
||||||
|
|
||||||
if (playerList.isEmpty()) {
|
if (playerList.isEmpty()) {
|
||||||
@ -240,11 +234,12 @@ public class MprisNowPlayingFragment extends Fragment implements VolumeKeyListen
|
|||||||
if (pos >= playerList.size()) return;
|
if (pos >= playerList.size()) return;
|
||||||
|
|
||||||
String player = playerList.get(pos);
|
String player = playerList.get(pos);
|
||||||
if (targetPlayer != null && player.equals(targetPlayer.getPlayer())) {
|
if (targetPlayer != null && player.equals(targetPlayer.getPlayerName())) {
|
||||||
return; //Player hasn't actually changed
|
return; //Player hasn't actually changed
|
||||||
}
|
}
|
||||||
targetPlayer = mpris.getPlayerStatus(player);
|
targetPlayer = plugin.getPlayerStatus(player);
|
||||||
updatePlayerStatus(mpris);
|
targetPlayerName = targetPlayer.getPlayerName();
|
||||||
|
updatePlayerStatus(plugin);
|
||||||
|
|
||||||
if (targetPlayer != null && targetPlayer.isPlaying()) {
|
if (targetPlayer != null && targetPlayer.isPlaying()) {
|
||||||
MprisMediaSession.getInstance().playerSelected(targetPlayer);
|
MprisMediaSession.getInstance().playerSelected(targetPlayer);
|
||||||
@ -259,11 +254,11 @@ public class MprisNowPlayingFragment extends Fragment implements VolumeKeyListen
|
|||||||
|
|
||||||
if (targetPlayer == null) {
|
if (targetPlayer == null) {
|
||||||
//If no player is selected, try to select a playing player
|
//If no player is selected, try to select a playing player
|
||||||
targetPlayer = mpris.getPlayingPlayer();
|
targetPlayer = plugin.getPlayingPlayer();
|
||||||
}
|
}
|
||||||
//Try to select the specified player
|
//Try to select the specified player
|
||||||
if (targetPlayer != null) {
|
if (targetPlayer != null) {
|
||||||
int targetIndex = adapter.getPosition(targetPlayer.getPlayer());
|
int targetIndex = adapter.getPosition(targetPlayer.getPlayerName());
|
||||||
if (targetIndex >= 0) {
|
if (targetIndex >= 0) {
|
||||||
mprisControlBinding.playerSpinner.setSelection(targetIndex);
|
mprisControlBinding.playerSpinner.setSelection(targetIndex);
|
||||||
} else {
|
} else {
|
||||||
@ -272,33 +267,30 @@ public class MprisNowPlayingFragment extends Fragment implements VolumeKeyListen
|
|||||||
}
|
}
|
||||||
//If no player selected, select the first one (if any)
|
//If no player selected, select the first one (if any)
|
||||||
if (targetPlayer == null && !playerList.isEmpty()) {
|
if (targetPlayer == null && !playerList.isEmpty()) {
|
||||||
targetPlayer = mpris.getPlayerStatus(playerList.get(0));
|
targetPlayer = plugin.getPlayerStatus(playerList.get(0));
|
||||||
mprisControlBinding.playerSpinner.setSelection(0);
|
mprisControlBinding.playerSpinner.setSelection(0);
|
||||||
}
|
}
|
||||||
updatePlayerStatus(mpris);
|
updatePlayerStatus(plugin);
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
super.onDestroy();
|
|
||||||
BackgroundService.RunCommand(requireContext(), service -> service.removeConnectionListener(connectionReceiver));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void performActionOnClick(View v, MprisPlayerCallback l) {
|
|
||||||
v.setOnClickListener(view -> BackgroundService.RunCommand(requireContext(), service -> {
|
|
||||||
if (targetPlayer == null) return;
|
|
||||||
l.performAction(targetPlayer);
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePlayerStatus(MprisPlugin mpris) {
|
private void performActionOnClick(View v, MprisPlayerCallback l) {
|
||||||
|
v.setOnClickListener(view -> {
|
||||||
|
if (targetPlayer == null) return;
|
||||||
|
l.performAction(targetPlayer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePlayerStatus(MprisPlugin plugin) {
|
||||||
|
if (!isAdded()) {
|
||||||
|
//Fragment is not attached to an activity. We will crash if we try to do anything here.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MprisPlugin.MprisPlayer playerStatus = targetPlayer;
|
MprisPlugin.MprisPlayer playerStatus = targetPlayer;
|
||||||
if (playerStatus == null) {
|
if (playerStatus == null) {
|
||||||
//No player with that name found, just display "empty" data
|
//No player with that name found, just display "empty" data
|
||||||
playerStatus = mpris.getEmptyPlayer();
|
playerStatus = plugin.getEmptyPlayer();
|
||||||
}
|
}
|
||||||
String song = playerStatus.getCurrentSong();
|
String song = playerStatus.getCurrentSong();
|
||||||
|
|
||||||
@ -433,7 +425,7 @@ public class MprisNowPlayingFragment extends Fragment implements VolumeKeyListen
|
|||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||||
if (targetPlayer != null) {
|
if (targetPlayer != null) {
|
||||||
outState.putString("targetPlayer", targetPlayer.getPlayer());
|
outState.putString("targetPlayer", targetPlayerName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,8 +11,6 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
@ -77,12 +75,12 @@ public class MprisPlugin extends Plugin {
|
|||||||
return album;
|
return album;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPlayer() {
|
public String getPlayerName() {
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isSpotify() {
|
boolean isSpotify() {
|
||||||
return getPlayer().equalsIgnoreCase("spotify");
|
return getPlayerName().equalsIgnoreCase("spotify");
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLoopStatus() {
|
public String getLoopStatus() {
|
||||||
@ -165,55 +163,55 @@ public class MprisPlugin extends Plugin {
|
|||||||
|
|
||||||
public void playPause() {
|
public void playPause() {
|
||||||
if (isPauseAllowed() || isPlayAllowed()) {
|
if (isPauseAllowed() || isPlayAllowed()) {
|
||||||
MprisPlugin.this.sendCommand(getPlayer(), "action", "PlayPause");
|
sendCommand(getPlayerName(), "action", "PlayPause");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void play() {
|
public void play() {
|
||||||
if (isPlayAllowed()) {
|
if (isPlayAllowed()) {
|
||||||
MprisPlugin.this.sendCommand(getPlayer(), "action", "Play");
|
sendCommand(getPlayerName(), "action", "Play");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pause() {
|
public void pause() {
|
||||||
if (isPauseAllowed()) {
|
if (isPauseAllowed()) {
|
||||||
MprisPlugin.this.sendCommand(getPlayer(), "action", "Pause");
|
sendCommand(getPlayerName(), "action", "Pause");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
MprisPlugin.this.sendCommand(getPlayer(), "action", "Stop");
|
sendCommand(getPlayerName(), "action", "Stop");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void previous() {
|
public void previous() {
|
||||||
if (isGoPreviousAllowed()) {
|
if (isGoPreviousAllowed()) {
|
||||||
MprisPlugin.this.sendCommand(getPlayer(), "action", "Previous");
|
sendCommand(getPlayerName(), "action", "Previous");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void next() {
|
public void next() {
|
||||||
if (isGoNextAllowed()) {
|
if (isGoNextAllowed()) {
|
||||||
MprisPlugin.this.sendCommand(getPlayer(), "action", "Next");
|
sendCommand(getPlayerName(), "action", "Next");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLoopStatus(String loopStatus) {
|
public void setLoopStatus(String loopStatus) {
|
||||||
MprisPlugin.this.sendCommand(getPlayer(), "setLoopStatus", loopStatus);
|
sendCommand(getPlayerName(), "setLoopStatus", loopStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setShuffle(boolean shuffle) {
|
public void setShuffle(boolean shuffle) {
|
||||||
MprisPlugin.this.sendCommand(getPlayer(), "setShuffle", shuffle);
|
sendCommand(getPlayerName(), "setShuffle", shuffle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVolume(int volume) {
|
public void setVolume(int volume) {
|
||||||
if (isSetVolumeAllowed()) {
|
if (isSetVolumeAllowed()) {
|
||||||
MprisPlugin.this.sendCommand(getPlayer(), "setVolume", volume);
|
sendCommand(getPlayerName(), "setVolume", volume);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPosition(int position) {
|
public void setPosition(int position) {
|
||||||
if (isSeekAllowed()) {
|
if (isSeekAllowed()) {
|
||||||
MprisPlugin.this.sendCommand(getPlayer(), "SetPosition", position);
|
sendCommand(getPlayerName(), "SetPosition", position);
|
||||||
|
|
||||||
lastPosition = position;
|
lastPosition = position;
|
||||||
lastPositionTime = System.currentTimeMillis();
|
lastPositionTime = System.currentTimeMillis();
|
||||||
@ -222,7 +220,7 @@ public class MprisPlugin extends Plugin {
|
|||||||
|
|
||||||
public void seek(int offset) {
|
public void seek(int offset) {
|
||||||
if (isSeekAllowed()) {
|
if (isSeekAllowed()) {
|
||||||
MprisPlugin.this.sendCommand(getPlayer(), "Seek", offset);
|
sendCommand(getPlayerName(), "Seek", offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -522,7 +520,7 @@ public class MprisPlugin extends Plugin {
|
|||||||
|
|
||||||
if (player.albumArtUrl.equals(url)) {
|
if (player.albumArtUrl.equals(url)) {
|
||||||
NetworkPacket np = new NetworkPacket(PACKET_TYPE_MPRIS_REQUEST);
|
NetworkPacket np = new NetworkPacket(PACKET_TYPE_MPRIS_REQUEST);
|
||||||
np.set("player", player.getPlayer());
|
np.set("player", player.getPlayerName());
|
||||||
np.set("albumArtUrl", url);
|
np.set("albumArtUrl", url);
|
||||||
device.sendPacket(np);
|
device.sendPacket(np);
|
||||||
return true;
|
return true;
|
||||||
|
@ -9,7 +9,7 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.core.content.FileProvider;
|
import androidx.core.content.FileProvider;
|
||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -58,13 +58,17 @@ public class PhotoActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
BackgroundService.RunWithPlugin(this, getIntent().getStringExtra("deviceId"), PhotoPlugin.class, plugin -> {
|
String deviceId = getIntent().getStringExtra("deviceId");
|
||||||
|
PhotoPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, PhotoPlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (resultCode == -1) {
|
if (resultCode == -1) {
|
||||||
plugin.sendPhoto(photoURI);
|
plugin.sendPhoto(photoURI);
|
||||||
} else {
|
} else {
|
||||||
plugin.sendCancel();
|
plugin.sendCancel();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,7 @@ import androidx.appcompat.app.AppCompatActivity;
|
|||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.media.VolumeProviderCompat;
|
import androidx.media.VolumeProviderCompat;
|
||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect.UserInterface.ThemeUtil;
|
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
import org.kde.kdeconnect_tp.databinding.ActivityPresenterBinding;
|
import org.kde.kdeconnect_tp.databinding.ActivityPresenterBinding;
|
||||||
|
|
||||||
@ -90,16 +89,14 @@ public class PresenterActivity extends AppCompatActivity implements SensorEventL
|
|||||||
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
|
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
|
||||||
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
||||||
|
|
||||||
final String deviceId = getIntent().getStringExtra("deviceId");
|
String deviceId = getIntent().getStringExtra("deviceId");
|
||||||
|
this.plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, PresenterPlugin.class);
|
||||||
|
|
||||||
BackgroundService.RunWithPlugin(this, deviceId, PresenterPlugin.class, plugin -> runOnUiThread(() -> {
|
|
||||||
this.plugin = plugin;
|
|
||||||
binding.nextButton.setOnClickListener(v -> plugin.sendNext());
|
binding.nextButton.setOnClickListener(v -> plugin.sendNext());
|
||||||
binding.previousButton.setOnClickListener(v -> plugin.sendPrevious());
|
binding.previousButton.setOnClickListener(v -> plugin.sendPrevious());
|
||||||
if (plugin.isPointerSupported()) {
|
if (plugin.isPointerSupported()) {
|
||||||
enablePointer();
|
enablePointer();
|
||||||
}
|
}
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
@ -23,9 +23,8 @@ import androidx.core.content.ContextCompat;
|
|||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect.UserInterface.List.ListAdapter;
|
import org.kde.kdeconnect.UserInterface.List.ListAdapter;
|
||||||
import org.kde.kdeconnect.UserInterface.ThemeUtil;
|
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
import org.kde.kdeconnect_tp.databinding.ActivityRunCommandBinding;
|
import org.kde.kdeconnect_tp.databinding.ActivityRunCommandBinding;
|
||||||
|
|
||||||
@ -38,11 +37,16 @@ import java.util.Objects;
|
|||||||
public class RunCommandActivity extends AppCompatActivity {
|
public class RunCommandActivity extends AppCompatActivity {
|
||||||
private ActivityRunCommandBinding binding;
|
private ActivityRunCommandBinding binding;
|
||||||
private String deviceId;
|
private String deviceId;
|
||||||
private final RunCommandPlugin.CommandsChangedCallback commandsChangedCallback = this::updateView;
|
private final RunCommandPlugin.CommandsChangedCallback commandsChangedCallback = () -> runOnUiThread(this::updateView);
|
||||||
private List<CommandEntry> commandItems;
|
private List<CommandEntry> commandItems;
|
||||||
|
|
||||||
private void updateView() {
|
private void updateView() {
|
||||||
BackgroundService.RunWithPlugin(this, deviceId, RunCommandPlugin.class, plugin -> runOnUiThread(() -> {
|
RunCommandPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, RunCommandPlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
registerForContextMenu(binding.runCommandsList);
|
registerForContextMenu(binding.runCommandsList);
|
||||||
|
|
||||||
commandItems = new ArrayList<>();
|
commandItems = new ArrayList<>();
|
||||||
@ -69,7 +73,6 @@ public class RunCommandActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
binding.addComandExplanation.setText(text);
|
binding.addComandExplanation.setText(text);
|
||||||
binding.addComandExplanation.setVisibility(commandItems.isEmpty() ? View.VISIBLE : View.GONE);
|
binding.addComandExplanation.setVisibility(commandItems.isEmpty() ? View.VISIBLE : View.GONE);
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -84,27 +87,22 @@ public class RunCommandActivity extends AppCompatActivity {
|
|||||||
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
||||||
|
|
||||||
deviceId = getIntent().getStringExtra("deviceId");
|
deviceId = getIntent().getStringExtra("deviceId");
|
||||||
|
RunCommandPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId,RunCommandPlugin.class);
|
||||||
boolean canAddCommands = false;
|
if (plugin != null) {
|
||||||
try {
|
if (plugin.canAddCommand()) {
|
||||||
canAddCommands = BackgroundService.getInstance().getDevice(deviceId).getPlugin(RunCommandPlugin.class).canAddCommand();
|
|
||||||
} catch (Exception ignore) {
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canAddCommands) {
|
|
||||||
binding.addCommandButton.show();
|
binding.addCommandButton.show();
|
||||||
} else {
|
} else {
|
||||||
binding.addCommandButton.hide();
|
binding.addCommandButton.hide();
|
||||||
}
|
}
|
||||||
|
binding.addCommandButton.setOnClickListener(v -> {
|
||||||
binding.addCommandButton.setOnClickListener(v -> BackgroundService.RunWithPlugin(RunCommandActivity.this, deviceId, RunCommandPlugin.class, plugin -> {
|
|
||||||
plugin.sendSetupPacket();
|
plugin.sendSetupPacket();
|
||||||
new AlertDialog.Builder(RunCommandActivity.this)
|
new AlertDialog.Builder(RunCommandActivity.this)
|
||||||
.setTitle(R.string.add_command)
|
.setTitle(R.string.add_command)
|
||||||
.setMessage(R.string.add_command_description)
|
.setMessage(R.string.add_command_description)
|
||||||
.setPositiveButton(R.string.ok, null)
|
.setPositiveButton(R.string.ok, null)
|
||||||
.show();
|
.show();
|
||||||
}));
|
});
|
||||||
|
}
|
||||||
updateView();
|
updateView();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,14 +132,23 @@ public class RunCommandActivity extends AppCompatActivity {
|
|||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
BackgroundService.RunWithPlugin(this, deviceId, RunCommandPlugin.class, plugin -> plugin.addCommandsUpdatedCallback(commandsChangedCallback));
|
RunCommandPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, RunCommandPlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
plugin.addCommandsUpdatedCallback(commandsChangedCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
|
|
||||||
BackgroundService.RunWithPlugin(this, deviceId, RunCommandPlugin.class, plugin -> plugin.removeCommandsUpdatedCallback(commandsChangedCallback));
|
RunCommandPlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, RunCommandPlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
plugin.removeCommandsUpdatedCallback(commandsChangedCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -23,8 +23,8 @@ import io.reactivex.Flowable
|
|||||||
import io.reactivex.processors.ReplayProcessor
|
import io.reactivex.processors.ReplayProcessor
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import org.kde.kdeconnect.BackgroundService
|
|
||||||
import org.kde.kdeconnect.Device
|
import org.kde.kdeconnect.Device
|
||||||
|
import org.kde.kdeconnect.KdeConnect
|
||||||
import org.kde.kdeconnect.UserInterface.MainActivity
|
import org.kde.kdeconnect.UserInterface.MainActivity
|
||||||
import org.kde.kdeconnect_tp.R
|
import org.kde.kdeconnect_tp.R
|
||||||
import org.reactivestreams.FlowAdapters
|
import org.reactivestreams.FlowAdapters
|
||||||
@ -92,12 +92,10 @@ class RunCommandControlsProviderService : ControlsProviderService() {
|
|||||||
if (action is CommandAction) {
|
if (action is CommandAction) {
|
||||||
val commandEntry = getCommandByControlId(controlId)
|
val commandEntry = getCommandByControlId(controlId)
|
||||||
if (commandEntry != null) {
|
if (commandEntry != null) {
|
||||||
val plugin = BackgroundService.getInstance().getDevice(controlId.split(":")[0]).getPlugin(RunCommandPlugin::class.java)
|
val deviceId = controlId.split(":")[0]
|
||||||
|
val plugin = KdeConnect.getInstance().getDevicePlugin(deviceId ,RunCommandPlugin::class.java)
|
||||||
if (plugin != null) {
|
if (plugin != null) {
|
||||||
BackgroundService.RunCommand(this) {
|
|
||||||
plugin.runCommand(commandEntry.key)
|
plugin.runCommand(commandEntry.key)
|
||||||
}
|
|
||||||
|
|
||||||
consumer.accept(ControlAction.RESPONSE_OK)
|
consumer.accept(ControlAction.RESPONSE_OK)
|
||||||
} else {
|
} else {
|
||||||
consumer.accept(ControlAction.RESPONSE_FAIL)
|
consumer.accept(ControlAction.RESPONSE_FAIL)
|
||||||
@ -141,9 +139,7 @@ class RunCommandControlsProviderService : ControlsProviderService() {
|
|||||||
private fun getAllCommandsList(): List<CommandEntryWithDevice> {
|
private fun getAllCommandsList(): List<CommandEntryWithDevice> {
|
||||||
val commandList = mutableListOf<CommandEntryWithDevice>()
|
val commandList = mutableListOf<CommandEntryWithDevice>()
|
||||||
|
|
||||||
val service = BackgroundService.getInstance() ?: return commandList
|
for (device in KdeConnect.getInstance().devices.values) {
|
||||||
|
|
||||||
for (device in service.devices.values) {
|
|
||||||
if (!device.isReachable) {
|
if (!device.isReachable) {
|
||||||
commandList.addAll(getSavedCommandsList(device))
|
commandList.addAll(getSavedCommandsList(device))
|
||||||
continue
|
continue
|
||||||
@ -169,9 +165,7 @@ class RunCommandControlsProviderService : ControlsProviderService() {
|
|||||||
private fun getCommandByControlId(controlId: String): CommandEntryWithDevice? {
|
private fun getCommandByControlId(controlId: String): CommandEntryWithDevice? {
|
||||||
val controlIdParts = controlId.split(":")
|
val controlIdParts = controlId.split(":")
|
||||||
|
|
||||||
val service = BackgroundService.getInstance() ?: return null
|
val device = KdeConnect.getInstance().getDevice(controlIdParts[0])
|
||||||
|
|
||||||
val device = service.getDevice(controlIdParts[0])
|
|
||||||
|
|
||||||
if (device == null || !device.isPaired) return null
|
if (device == null || !device.isPaired) return null
|
||||||
|
|
||||||
|
@ -10,9 +10,8 @@ import android.widget.TextView;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
|
||||||
import org.kde.kdeconnect.Device;
|
import org.kde.kdeconnect.Device;
|
||||||
import org.kde.kdeconnect.UserInterface.ThemeUtil;
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
|
|
||||||
public class RunCommandUrlActivity extends AppCompatActivity {
|
public class RunCommandUrlActivity extends AppCompatActivity {
|
||||||
@ -26,8 +25,7 @@ public class RunCommandUrlActivity extends AppCompatActivity {
|
|||||||
Uri uri = getIntent().getData();
|
Uri uri = getIntent().getData();
|
||||||
String deviceId = uri.getPathSegments().get(0);
|
String deviceId = uri.getPathSegments().get(0);
|
||||||
|
|
||||||
BackgroundService.RunCommand(this, service -> {
|
final Device device = KdeConnect.getInstance().getDevice(deviceId);
|
||||||
final Device device = service.getDevice(deviceId);
|
|
||||||
|
|
||||||
if(device == null) {
|
if(device == null) {
|
||||||
error(R.string.runcommand_nosuchdevice);
|
error(R.string.runcommand_nosuchdevice);
|
||||||
@ -54,12 +52,11 @@ public class RunCommandUrlActivity extends AppCompatActivity {
|
|||||||
RunCommandUrlActivity.this.finish();
|
RunCommandUrlActivity.this.finish();
|
||||||
|
|
||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
|
||||||
Vibrator vibrator = RunCommandUrlActivity.this.getSystemService(Vibrator.class);
|
Vibrator vibrator = getSystemService(Vibrator.class);
|
||||||
if(vibrator != null && vibrator.hasVibrator()) {
|
if(vibrator != null && vibrator.hasVibrator()) {
|
||||||
vibrator.vibrate(100);
|
vibrator.vibrate(100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e("RuncommandPlugin", "Exception", e);
|
Log.e("RuncommandPlugin", "Exception", e);
|
||||||
}
|
}
|
||||||
|
@ -12,10 +12,12 @@ import android.util.Log;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.RemoteViews;
|
import android.widget.RemoteViews;
|
||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
|
||||||
import org.kde.kdeconnect.Device;
|
import org.kde.kdeconnect.Device;
|
||||||
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class RunCommandWidget extends AppWidgetProvider {
|
public class RunCommandWidget extends AppWidgetProvider {
|
||||||
|
|
||||||
public static final String RUN_COMMAND_ACTION = "RUN_COMMAND_ACTION";
|
public static final String RUN_COMMAND_ACTION = "RUN_COMMAND_ACTION";
|
||||||
@ -35,8 +37,7 @@ public class RunCommandWidget extends AppWidgetProvider {
|
|||||||
final String targetCommand = intent.getStringExtra(TARGET_COMMAND);
|
final String targetCommand = intent.getStringExtra(TARGET_COMMAND);
|
||||||
final String targetDevice = intent.getStringExtra(TARGET_DEVICE);
|
final String targetDevice = intent.getStringExtra(TARGET_DEVICE);
|
||||||
|
|
||||||
BackgroundService.RunCommand(context, service -> {
|
RunCommandPlugin plugin = KdeConnect.getInstance().getDevicePlugin(targetDevice, RunCommandPlugin.class);
|
||||||
RunCommandPlugin plugin = service.getDevice(targetDevice).getPlugin(RunCommandPlugin.class);
|
|
||||||
|
|
||||||
if (plugin != null) {
|
if (plugin != null) {
|
||||||
try {
|
try {
|
||||||
@ -46,7 +47,6 @@ public class RunCommandWidget extends AppWidgetProvider {
|
|||||||
Log.e("RunCommandWidget", "Error running command", ex);
|
Log.e("RunCommandWidget", "Error running command", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
} else if (intent != null && TextUtils.equals(intent.getAction(), SET_CURRENT_DEVICE)) {
|
} else if (intent != null && TextUtils.equals(intent.getAction(), SET_CURRENT_DEVICE)) {
|
||||||
setCurrentDevice(context);
|
setCurrentDevice(context);
|
||||||
}
|
}
|
||||||
@ -70,14 +70,13 @@ public class RunCommandWidget extends AppWidgetProvider {
|
|||||||
|
|
||||||
private void updateWidget(final Context context) {
|
private void updateWidget(final Context context) {
|
||||||
|
|
||||||
if (getCurrentDevice() == null || !getCurrentDevice().isReachable()) {
|
Device device = getCurrentDevice();
|
||||||
|
|
||||||
BackgroundService.RunCommand(context, service -> {
|
if (device == null || !device.isReachable()) {
|
||||||
if (service.getDevices().size() > 0)
|
ConcurrentHashMap<String, Device> devices = KdeConnect.getInstance().getDevices();
|
||||||
currentDeviceId = service.getDevices().elements().nextElement().getDeviceId();
|
if (devices.size() > 0) {
|
||||||
|
currentDeviceId = devices.elements().nextElement().getDeviceId();
|
||||||
updateWidgetImpl(context);
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateWidgetImpl(context);
|
updateWidgetImpl(context);
|
||||||
@ -99,12 +98,13 @@ public class RunCommandWidget extends AppWidgetProvider {
|
|||||||
pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
||||||
views.setOnClickPendingIntent(R.id.runcommandWidgetTitleHeader, pendingIntent);
|
views.setOnClickPendingIntent(R.id.runcommandWidgetTitleHeader, pendingIntent);
|
||||||
|
|
||||||
if (getCurrentDevice() == null || !getCurrentDevice().isReachable()) {
|
Device device = getCurrentDevice();
|
||||||
|
if (device == null || !device.isReachable()) {
|
||||||
views.setTextViewText(R.id.runcommandWidgetTitle, context.getString(R.string.kde_connect));
|
views.setTextViewText(R.id.runcommandWidgetTitle, context.getString(R.string.kde_connect));
|
||||||
views.setViewVisibility(R.id.run_commands_list, View.GONE);
|
views.setViewVisibility(R.id.run_commands_list, View.GONE);
|
||||||
views.setViewVisibility(R.id.not_reachable_message, View.VISIBLE);
|
views.setViewVisibility(R.id.not_reachable_message, View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
views.setTextViewText(R.id.runcommandWidgetTitle, getCurrentDevice().getName());
|
views.setTextViewText(R.id.runcommandWidgetTitle, device.getName());
|
||||||
views.setViewVisibility(R.id.run_commands_list, View.VISIBLE);
|
views.setViewVisibility(R.id.run_commands_list, View.VISIBLE);
|
||||||
views.setViewVisibility(R.id.not_reachable_message, View.GONE);
|
views.setViewVisibility(R.id.not_reachable_message, View.GONE);
|
||||||
}
|
}
|
||||||
@ -129,21 +129,15 @@ public class RunCommandWidget extends AppWidgetProvider {
|
|||||||
Log.e("RunCommandWidget", "Error updating widget", ex);
|
Log.e("RunCommandWidget", "Error updating widget", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BackgroundService.getInstance() != null) {
|
|
||||||
BackgroundService.getInstance().addDeviceListChangedCallback("RunCommandWidget", unused -> {
|
KdeConnect.getInstance().addDeviceListChangedCallback("RunCommandWidget", () -> {
|
||||||
Intent updateWidget = new Intent(context, RunCommandWidget.class);
|
Intent updateWidget = new Intent(context, RunCommandWidget.class);
|
||||||
context.sendBroadcast(updateWidget);
|
context.sendBroadcast(updateWidget);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static Device getCurrentDevice() {
|
public static Device getCurrentDevice() {
|
||||||
|
return KdeConnect.getInstance().getDevice(currentDeviceId);
|
||||||
try {
|
|
||||||
return BackgroundService.getInstance().getDevice(currentDeviceId);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setCurrentDevice(final String DeviceId) {
|
public static void setCurrentDevice(final String DeviceId) {
|
||||||
|
@ -6,10 +6,9 @@ import android.view.Window;
|
|||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
|
||||||
import org.kde.kdeconnect.Device;
|
import org.kde.kdeconnect.Device;
|
||||||
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect.UserInterface.List.ListAdapter;
|
import org.kde.kdeconnect.UserInterface.List.ListAdapter;
|
||||||
import org.kde.kdeconnect.UserInterface.ThemeUtil;
|
|
||||||
import org.kde.kdeconnect_tp.databinding.WidgetRemoteCommandPluginDialogBinding;
|
import org.kde.kdeconnect_tp.databinding.WidgetRemoteCommandPluginDialogBinding;
|
||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@ -27,8 +26,7 @@ public class RunCommandWidgetDeviceSelector extends AppCompatActivity {
|
|||||||
WidgetRemoteCommandPluginDialogBinding.inflate(getLayoutInflater());
|
WidgetRemoteCommandPluginDialogBinding.inflate(getLayoutInflater());
|
||||||
setContentView(binding.getRoot());
|
setContentView(binding.getRoot());
|
||||||
|
|
||||||
BackgroundService.RunCommand(this, service -> runOnUiThread(() -> {
|
final List<CommandEntry> deviceItems = KdeConnect.getInstance().getDevices().values().stream()
|
||||||
final List<CommandEntry> deviceItems = service.getDevices().values().stream()
|
|
||||||
.filter(Device::isPaired).filter(Device::isReachable)
|
.filter(Device::isPaired).filter(Device::isReachable)
|
||||||
.map(device -> new CommandEntry(device.getName(), null, device.getDeviceId()))
|
.map(device -> new CommandEntry(device.getName(), null, device.getDeviceId()))
|
||||||
.sorted(Comparator.comparing(CommandEntry::getName))
|
.sorted(Comparator.comparing(CommandEntry::getName))
|
||||||
@ -46,6 +44,5 @@ public class RunCommandWidgetDeviceSelector extends AppCompatActivity {
|
|||||||
|
|
||||||
finish();
|
finish();
|
||||||
});
|
});
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -30,8 +30,8 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
|
||||||
import org.kde.kdeconnect.Device;
|
import org.kde.kdeconnect.Device;
|
||||||
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect.Plugins.Plugin;
|
import org.kde.kdeconnect.Plugins.Plugin;
|
||||||
import org.kde.kdeconnect.UserInterface.PluginSettingsActivity;
|
import org.kde.kdeconnect.UserInterface.PluginSettingsActivity;
|
||||||
import org.kde.kdeconnect.UserInterface.PluginSettingsFragment;
|
import org.kde.kdeconnect.UserInterface.PluginSettingsFragment;
|
||||||
@ -326,21 +326,11 @@ public class SftpSettingsFragment
|
|||||||
|
|
||||||
addStoragePreferences(preferenceCategory);
|
addStoragePreferences(preferenceCategory);
|
||||||
|
|
||||||
Device device = getDeviceOrThrow();
|
Device device = KdeConnect.getInstance().getDevice(getDeviceId());
|
||||||
|
|
||||||
device.reloadPluginsFromSettings();
|
device.reloadPluginsFromSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Device getDeviceOrThrow() {
|
|
||||||
Device device = BackgroundService.getInstance().getDevice(getDeviceId());
|
|
||||||
|
|
||||||
if (device == null) {
|
|
||||||
throw new RuntimeException("SftpSettingsFragment.getDeviceOrThrow(): No device with id: " + getDeviceId());
|
|
||||||
}
|
|
||||||
|
|
||||||
return device;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) {
|
public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) {
|
||||||
SftpPlugin.StorageInfo newStorageInfo = (SftpPlugin.StorageInfo) newValue;
|
SftpPlugin.StorageInfo newStorageInfo = (SftpPlugin.StorageInfo) newValue;
|
||||||
|
@ -16,8 +16,7 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect.UserInterface.ThemeUtil;
|
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -69,7 +68,12 @@ public class SendFileActivity extends AppCompatActivity {
|
|||||||
if (uris.isEmpty()) {
|
if (uris.isEmpty()) {
|
||||||
Log.w("SendFileActivity", "No files to send?");
|
Log.w("SendFileActivity", "No files to send?");
|
||||||
} else {
|
} else {
|
||||||
BackgroundService.RunWithPlugin(this, mDeviceId, SharePlugin.class, plugin -> plugin.sendUriList(uris));
|
SharePlugin plugin = KdeConnect.getInstance().getDevicePlugin(mDeviceId, SharePlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
plugin.sendUriList(uris);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finish();
|
finish();
|
||||||
|
@ -17,10 +17,10 @@ import androidx.appcompat.app.AppCompatActivity;
|
|||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
import org.kde.kdeconnect.BackgroundService;
|
||||||
import org.kde.kdeconnect.Device;
|
import org.kde.kdeconnect.Device;
|
||||||
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect.UserInterface.List.EntryItemWithIcon;
|
import org.kde.kdeconnect.UserInterface.List.EntryItemWithIcon;
|
||||||
import org.kde.kdeconnect.UserInterface.List.ListAdapter;
|
import org.kde.kdeconnect.UserInterface.List.ListAdapter;
|
||||||
import org.kde.kdeconnect.UserInterface.List.SectionItem;
|
import org.kde.kdeconnect.UserInterface.List.SectionItem;
|
||||||
import org.kde.kdeconnect.UserInterface.ThemeUtil;
|
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
import org.kde.kdeconnect_tp.databinding.ActivityShareBinding;
|
import org.kde.kdeconnect_tp.databinding.ActivityShareBinding;
|
||||||
|
|
||||||
@ -42,19 +42,17 @@ public class ShareActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||||
if (item.getItemId() == R.id.menu_refresh) {
|
if (item.getItemId() == R.id.menu_refresh) {
|
||||||
updateDeviceListAction();
|
refreshDevicesAction();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateDeviceListAction() {
|
private void refreshDevicesAction() {
|
||||||
updateDeviceList();
|
BackgroundService.ForceRefreshConnections(this);
|
||||||
BackgroundService.RunCommand(ShareActivity.this, BackgroundService::onNetworkChange);
|
|
||||||
|
|
||||||
binding.devicesListLayout.refreshListLayout.setRefreshing(true);
|
binding.devicesListLayout.refreshListLayout.setRefreshing(true);
|
||||||
|
|
||||||
binding.devicesListLayout.refreshListLayout.postDelayed(() -> {
|
binding.devicesListLayout.refreshListLayout.postDelayed(() -> {
|
||||||
binding.devicesListLayout.refreshListLayout.setRefreshing(false);
|
binding.devicesListLayout.refreshListLayout.setRefreshing(false);
|
||||||
}, 1500);
|
}, 1500);
|
||||||
@ -69,9 +67,7 @@ public class ShareActivity extends AppCompatActivity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BackgroundService.RunCommand(this, service -> {
|
Collection<Device> devices = KdeConnect.getInstance().getDevices().values();
|
||||||
|
|
||||||
Collection<Device> devices = service.getDevices().values();
|
|
||||||
final ArrayList<Device> devicesList = new ArrayList<>();
|
final ArrayList<Device> devicesList = new ArrayList<>();
|
||||||
final ArrayList<ListAdapter.Item> items = new ArrayList<>();
|
final ArrayList<ListAdapter.Item> items = new ArrayList<>();
|
||||||
|
|
||||||
@ -86,15 +82,15 @@ public class ShareActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
runOnUiThread(() -> {
|
|
||||||
binding.devicesListLayout.devicesList.setAdapter(new ListAdapter(ShareActivity.this, items));
|
binding.devicesListLayout.devicesList.setAdapter(new ListAdapter(ShareActivity.this, items));
|
||||||
binding.devicesListLayout.devicesList.setOnItemClickListener((adapterView, view, i, l) -> {
|
binding.devicesListLayout.devicesList.setOnItemClickListener((adapterView, view, i, l) -> {
|
||||||
Device device = devicesList.get(i - 1); //NOTE: -1 because of the title!
|
Device device = devicesList.get(i - 1); //NOTE: -1 because of the title!
|
||||||
BackgroundService.RunWithPlugin(this, device.getDeviceId(), SharePlugin.class, plugin -> plugin.share(intent));
|
SharePlugin plugin = KdeConnect.getInstance().getDevicePlugin(device.getDeviceId(), SharePlugin.class);
|
||||||
|
if (plugin != null) {
|
||||||
|
plugin.share(intent);
|
||||||
|
}
|
||||||
finish();
|
finish();
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -109,7 +105,7 @@ public class ShareActivity extends AppCompatActivity {
|
|||||||
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
getSupportActionBar().setDisplayShowHomeEnabled(true);
|
||||||
|
|
||||||
ActionBar actionBar = getSupportActionBar();
|
ActionBar actionBar = getSupportActionBar();
|
||||||
binding.devicesListLayout.refreshListLayout.setOnRefreshListener(this::updateDeviceListAction);
|
binding.devicesListLayout.refreshListLayout.setOnRefreshListener(this::refreshDevicesAction);
|
||||||
if (actionBar != null) {
|
if (actionBar != null) {
|
||||||
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM);
|
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM);
|
||||||
}
|
}
|
||||||
@ -123,22 +119,21 @@ public class ShareActivity extends AppCompatActivity {
|
|||||||
final String deviceId = intent.getStringExtra("deviceId");
|
final String deviceId = intent.getStringExtra("deviceId");
|
||||||
|
|
||||||
if (deviceId != null) {
|
if (deviceId != null) {
|
||||||
BackgroundService.RunWithPlugin(this, deviceId, SharePlugin.class, plugin -> {
|
SharePlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, SharePlugin.class);
|
||||||
|
if (plugin != null) {
|
||||||
plugin.share(intent);
|
plugin.share(intent);
|
||||||
|
}
|
||||||
finish();
|
finish();
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
BackgroundService.RunCommand(this, service -> {
|
KdeConnect.getInstance().addDeviceListChangedCallback("ShareActivity", () -> runOnUiThread(this::updateDeviceList));
|
||||||
service.onNetworkChange();
|
BackgroundService.ForceRefreshConnections(this); // force a network re-discover
|
||||||
service.addDeviceListChangedCallback("ShareActivity", unused -> updateDeviceList());
|
|
||||||
});
|
|
||||||
updateDeviceList();
|
updateDeviceList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStop() {
|
protected void onStop() {
|
||||||
BackgroundService.RunCommand(this, service -> service.removeDeviceListChangedCallback("ShareActivity"));
|
KdeConnect.getInstance().removeDeviceListChangedCallback("ShareActivity");
|
||||||
super.onStop();
|
super.onStop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
|
|
||||||
public class ShareBroadcastReceiver extends BroadcastReceiver {
|
public class ShareBroadcastReceiver extends BroadcastReceiver {
|
||||||
@Override
|
@Override
|
||||||
@ -35,6 +35,10 @@ public class ShareBroadcastReceiver extends BroadcastReceiver {
|
|||||||
long jobId = intent.getLongExtra(SharePlugin.CANCEL_SHARE_BACKGROUND_JOB_ID_EXTRA, -1);
|
long jobId = intent.getLongExtra(SharePlugin.CANCEL_SHARE_BACKGROUND_JOB_ID_EXTRA, -1);
|
||||||
String deviceId = intent.getStringExtra(SharePlugin.CANCEL_SHARE_DEVICE_ID_EXTRA);
|
String deviceId = intent.getStringExtra(SharePlugin.CANCEL_SHARE_DEVICE_ID_EXTRA);
|
||||||
|
|
||||||
BackgroundService.RunWithPlugin(context, deviceId, SharePlugin.class, plugin -> plugin.cancelJob(jobId));
|
SharePlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, SharePlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
plugin.cancelJob(jobId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,8 @@ import android.service.chooser.ChooserTarget;
|
|||||||
import android.service.chooser.ChooserTargetService;
|
import android.service.chooser.ChooserTargetService;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
|
||||||
import org.kde.kdeconnect.Device;
|
import org.kde.kdeconnect.Device;
|
||||||
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -26,7 +26,7 @@ public class ShareChooserTargetService extends ChooserTargetService {
|
|||||||
public List<ChooserTarget> onGetChooserTargets(ComponentName targetActivityName, IntentFilter matchedFilter) {
|
public List<ChooserTarget> onGetChooserTargets(ComponentName targetActivityName, IntentFilter matchedFilter) {
|
||||||
Log.d("DirectShare", "invoked");
|
Log.d("DirectShare", "invoked");
|
||||||
final List<ChooserTarget> targets = new ArrayList<>();
|
final List<ChooserTarget> targets = new ArrayList<>();
|
||||||
for (Device d : BackgroundService.getInstance().getDevices().values()) {
|
for (Device d : KdeConnect.getInstance().getDevices().values()) {
|
||||||
if (d.isReachable() && d.isPaired()) {
|
if (d.isReachable() && d.isPaired()) {
|
||||||
Log.d("DirectShare", d.getName());
|
Log.d("DirectShare", d.getName());
|
||||||
final String targetName = d.getName();
|
final String targetName = d.getName();
|
||||||
|
@ -15,7 +15,6 @@ import android.graphics.drawable.Drawable;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@ -157,7 +156,7 @@ public class SharePlugin extends Plugin {
|
|||||||
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||||
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
|
||||||
IntentHelper.startActivityFromBackground(context, browserIntent, url);
|
IntentHelper.startActivityFromBackgroundOrCreateNotification(context, browserIntent, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void receiveText(NetworkPacket np) {
|
private void receiveText(NetworkPacket np) {
|
||||||
|
@ -11,7 +11,6 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.core.util.Consumer;
|
import androidx.core.util.Consumer;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
import org.kde.kdeconnect_tp.databinding.ListItemSystemvolumeBinding;
|
import org.kde.kdeconnect_tp.databinding.ListItemSystemvolumeBinding;
|
||||||
|
|
||||||
@ -49,8 +48,7 @@ class SinkItemHolder extends RecyclerView.ViewHolder
|
|||||||
@Override
|
@Override
|
||||||
public void onProgressChanged(final SeekBar seekBar, int i, boolean triggeredByUser) {
|
public void onProgressChanged(final SeekBar seekBar, int i, boolean triggeredByUser) {
|
||||||
if (triggeredByUser) {
|
if (triggeredByUser) {
|
||||||
BackgroundService.RunCommand(seekBar.getContext(),
|
plugin.sendVolume(sink.getName(), seekBar.getProgress());
|
||||||
service -> plugin.sendVolume(sink.getName(), seekBar.getProgress()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,8 +60,7 @@ class SinkItemHolder extends RecyclerView.ViewHolder
|
|||||||
@Override
|
@Override
|
||||||
public void onStopTrackingTouch(final SeekBar seekBar) {
|
public void onStopTrackingTouch(final SeekBar seekBar) {
|
||||||
seekBarTracking.accept(false);
|
seekBarTracking.accept(false);
|
||||||
BackgroundService.RunCommand(seekBar.getContext(),
|
plugin.sendVolume(sink.getName(), seekBar.getProgress());
|
||||||
service -> plugin.sendVolume(sink.getName(), seekBar.getProgress()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
package org.kde.kdeconnect.Plugins.SystemVolumePlugin;
|
package org.kde.kdeconnect.Plugins.SystemVolumePlugin;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@ -20,8 +19,8 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
|||||||
import androidx.recyclerview.widget.ListAdapter;
|
import androidx.recyclerview.widget.ListAdapter;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
|
||||||
import org.kde.kdeconnect.Helpers.VolumeHelperKt;
|
import org.kde.kdeconnect.Helpers.VolumeHelperKt;
|
||||||
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect.Plugins.MprisPlugin.MprisPlugin;
|
import org.kde.kdeconnect.Plugins.MprisPlugin.MprisPlugin;
|
||||||
import org.kde.kdeconnect.Plugins.MprisPlugin.VolumeKeyListener;
|
import org.kde.kdeconnect.Plugins.MprisPlugin.VolumeKeyListener;
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
@ -73,19 +72,15 @@ public class SystemVolumeFragment
|
|||||||
recyclerView.setAdapter(recyclerAdapter);
|
recyclerView.setAdapter(recyclerAdapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connectToPlugin(getDeviceId());
|
||||||
|
|
||||||
return systemVolumeFragmentBinding.getRoot();
|
return systemVolumeFragmentBinding.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(@NonNull Context context) {
|
public void onDestroyView() {
|
||||||
super.onAttach(context);
|
|
||||||
connectToPlugin(getDeviceId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDetach() {
|
|
||||||
super.onDetach();
|
|
||||||
disconnectFromPlugin(getDeviceId());
|
disconnectFromPlugin(getDeviceId());
|
||||||
|
super.onDestroyView();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -99,16 +94,21 @@ public class SystemVolumeFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void connectToPlugin(final String deviceId) {
|
private void connectToPlugin(final String deviceId) {
|
||||||
BackgroundService.RunWithPlugin(requireActivity(), deviceId, SystemVolumePlugin.class, plugin -> {
|
SystemVolumePlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, SystemVolumePlugin.class);
|
||||||
|
if (plugin == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
plugin.addSinkListener(SystemVolumeFragment.this);
|
plugin.addSinkListener(SystemVolumeFragment.this);
|
||||||
plugin.requestSinkList();
|
plugin.requestSinkList();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void disconnectFromPlugin(final String deviceId) {
|
private void disconnectFromPlugin(final String deviceId) {
|
||||||
BackgroundService.RunWithPlugin(requireActivity(), deviceId, SystemVolumePlugin.class, plugin ->
|
SystemVolumePlugin plugin = KdeConnect.getInstance().getDevicePlugin(deviceId, SystemVolumePlugin.class);
|
||||||
plugin.removeSinkListener(SystemVolumeFragment.this));
|
if (plugin == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
plugin.removeSinkListener(SystemVolumeFragment.this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -18,11 +18,11 @@ import androidx.fragment.app.Fragment
|
|||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import org.kde.kdeconnect.BackgroundService
|
|
||||||
import org.kde.kdeconnect.Device
|
import org.kde.kdeconnect.Device
|
||||||
import org.kde.kdeconnect.Device.PairingCallback
|
import org.kde.kdeconnect.Device.PairingCallback
|
||||||
import org.kde.kdeconnect.Device.PluginsChangedListener
|
import org.kde.kdeconnect.Device.PluginsChangedListener
|
||||||
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper
|
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper
|
||||||
|
import org.kde.kdeconnect.KdeConnect
|
||||||
import org.kde.kdeconnect.Plugins.BatteryPlugin.BatteryPlugin
|
import org.kde.kdeconnect.Plugins.BatteryPlugin.BatteryPlugin
|
||||||
import org.kde.kdeconnect.Plugins.Plugin
|
import org.kde.kdeconnect.Plugins.Plugin
|
||||||
import org.kde.kdeconnect.UserInterface.List.PluginAdapter
|
import org.kde.kdeconnect.UserInterface.List.PluginAdapter
|
||||||
@ -98,9 +98,7 @@ class DeviceFragment : Fragment() {
|
|||||||
// ...and for when pairing doesn't (or can't) work
|
// ...and for when pairing doesn't (or can't) work
|
||||||
errorBinding = deviceBinding.pairError
|
errorBinding = deviceBinding.pairError
|
||||||
|
|
||||||
BackgroundService.RunCommand(mActivity) {
|
device = KdeConnect.getInstance().getDevice(deviceId)
|
||||||
device = it.getDevice(deviceId)
|
|
||||||
}
|
|
||||||
|
|
||||||
requirePairingBinding().pairButton.setOnClickListener {
|
requirePairingBinding().pairButton.setOnClickListener {
|
||||||
with(requirePairingBinding()) {
|
with(requirePairingBinding()) {
|
||||||
@ -128,36 +126,35 @@ class DeviceFragment : Fragment() {
|
|||||||
mActivity?.onDeviceSelected(null)
|
mActivity?.onDeviceSelected(null)
|
||||||
}
|
}
|
||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
BackgroundService.RunCommand(mActivity) { service: BackgroundService ->
|
|
||||||
device = service.getDevice(deviceId) ?: let {
|
|
||||||
Log.e(TAG, "Trying to display a device fragment but the device is not present")
|
|
||||||
mActivity?.onDeviceSelected(null)
|
|
||||||
return@RunCommand
|
|
||||||
}
|
|
||||||
mActivity?.supportActionBar?.title = device?.name
|
|
||||||
device?.addPairingCallback(pairingCallback)
|
|
||||||
device?.addPluginsChangedListener(pluginsChangedListener)
|
|
||||||
refreshUI()
|
|
||||||
}
|
|
||||||
|
|
||||||
requireDeviceBinding().pluginsList.layoutManager =
|
requireDeviceBinding().pluginsList.layoutManager =
|
||||||
GridLayoutManager(requireContext(), resources.getInteger(R.integer.plugins_columns))
|
GridLayoutManager(requireContext(), resources.getInteger(R.integer.plugins_columns))
|
||||||
requireDeviceBinding().permissionsList.layoutManager = LinearLayoutManager(requireContext())
|
requireDeviceBinding().permissionsList.layoutManager = LinearLayoutManager(requireContext())
|
||||||
|
|
||||||
|
device?.apply {
|
||||||
|
mActivity?.supportActionBar?.title = name
|
||||||
|
addPairingCallback(pairingCallback)
|
||||||
|
addPluginsChangedListener(pluginsChangedListener)
|
||||||
|
} ?: run { // device is null
|
||||||
|
Log.e(TAG, "Trying to display a device fragment but the device is not present")
|
||||||
|
mActivity?.onDeviceSelected(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshUI()
|
||||||
|
|
||||||
return deviceBinding.root
|
return deviceBinding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
private val pluginsChangedListener = PluginsChangedListener { refreshUI() }
|
private val pluginsChangedListener = PluginsChangedListener { refreshUI() }
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
BackgroundService.RunCommand(mActivity) { service: BackgroundService ->
|
device?.apply {
|
||||||
val device = service.getDevice(deviceId) ?: return@RunCommand
|
removePluginsChangedListener(pluginsChangedListener)
|
||||||
device.removePluginsChangedListener(pluginsChangedListener)
|
removePairingCallback(pairingCallback)
|
||||||
device.removePairingCallback(pairingCallback)
|
|
||||||
}
|
}
|
||||||
super.onDestroyView()
|
|
||||||
pairingBinding = null
|
pairingBinding = null
|
||||||
errorBinding = null
|
errorBinding = null
|
||||||
deviceBinding = null
|
deviceBinding = null
|
||||||
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||||
|
@ -25,6 +25,7 @@ import org.apache.commons.lang3.ArrayUtils
|
|||||||
import org.kde.kdeconnect.BackgroundService
|
import org.kde.kdeconnect.BackgroundService
|
||||||
import org.kde.kdeconnect.Device
|
import org.kde.kdeconnect.Device
|
||||||
import org.kde.kdeconnect.Helpers.DeviceHelper
|
import org.kde.kdeconnect.Helpers.DeviceHelper
|
||||||
|
import org.kde.kdeconnect.KdeConnect
|
||||||
import org.kde.kdeconnect.Plugins.SharePlugin.ShareSettingsFragment
|
import org.kde.kdeconnect.Plugins.SharePlugin.ShareSettingsFragment
|
||||||
import org.kde.kdeconnect.UserInterface.About.AboutFragment.Companion.newInstance
|
import org.kde.kdeconnect.UserInterface.About.AboutFragment.Companion.newInstance
|
||||||
import org.kde.kdeconnect.UserInterface.About.getApplicationAboutData
|
import org.kde.kdeconnect.UserInterface.About.getApplicationAboutData
|
||||||
@ -194,18 +195,16 @@ class MainActivity : AppCompatActivity(), OnSharedPreferenceChangeListener {
|
|||||||
private fun onPairResultFromNotification(deviceId: String?, pairStatus: String): String? {
|
private fun onPairResultFromNotification(deviceId: String?, pairStatus: String): String? {
|
||||||
assert(deviceId != null)
|
assert(deviceId != null)
|
||||||
if (pairStatus != PAIRING_PENDING) {
|
if (pairStatus != PAIRING_PENDING) {
|
||||||
BackgroundService.RunCommand(this) { service: BackgroundService ->
|
val device = KdeConnect.getInstance().getDevice(deviceId)
|
||||||
val device = service.getDevice(deviceId)
|
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
Log.w(this::class.simpleName, "Reject pairing - device no longer exists: $deviceId")
|
Log.w(this::class.simpleName, "Reject pairing - device no longer exists: $deviceId")
|
||||||
return@RunCommand
|
return null
|
||||||
}
|
}
|
||||||
when (pairStatus) {
|
when (pairStatus) {
|
||||||
PAIRING_ACCEPTED -> device.acceptPairing()
|
PAIRING_ACCEPTED -> device.acceptPairing()
|
||||||
PAIRING_REJECTED -> device.rejectPairing()
|
PAIRING_REJECTED -> device.rejectPairing()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return if (pairStatus == PAIRING_ACCEPTED || pairStatus == PAIRING_PENDING) deviceId else null
|
return if (pairStatus == PAIRING_ACCEPTED || pairStatus == PAIRING_PENDING) deviceId else null
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,13 +227,12 @@ class MainActivity : AppCompatActivity(), OnSharedPreferenceChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateDeviceList() {
|
private fun updateDeviceList() {
|
||||||
BackgroundService.RunCommand(this@MainActivity) { service: BackgroundService ->
|
|
||||||
val menu = mNavigationView.menu
|
val menu = mNavigationView.menu
|
||||||
menu.clear()
|
menu.clear()
|
||||||
mMapMenuToDeviceId.clear()
|
mMapMenuToDeviceId.clear()
|
||||||
val devicesMenu = menu.addSubMenu(R.string.devices)
|
val devicesMenu = menu.addSubMenu(R.string.devices)
|
||||||
var id = MENU_ENTRY_DEVICE_FIRST_ID
|
var id = MENU_ENTRY_DEVICE_FIRST_ID
|
||||||
val devices: Collection<Device> = service.devices.values
|
val devices: Collection<Device> = KdeConnect.getInstance().devices.values
|
||||||
for (device in devices) {
|
for (device in devices) {
|
||||||
if (device.isReachable && device.isPaired) {
|
if (device.isReachable && device.isPaired) {
|
||||||
val item = devicesMenu.add(Menu.FIRST, id++, 1, device.name)
|
val item = devicesMenu.add(Menu.FIRST, id++, 1, device.name)
|
||||||
@ -259,14 +257,11 @@ class MainActivity : AppCompatActivity(), OnSharedPreferenceChangeListener {
|
|||||||
}
|
}
|
||||||
mNavigationView.setCheckedItem(mCurrentMenuEntry)
|
mNavigationView.setCheckedItem(mCurrentMenuEntry)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
BackgroundService.RunCommand(this) { service: BackgroundService ->
|
BackgroundService.Start(applicationContext);
|
||||||
service.onNetworkChange()
|
KdeConnect.getInstance().addDeviceListChangedCallback(this::class.simpleName) { runOnUiThread { updateDeviceList() } }
|
||||||
service.addDeviceListChangedCallback(this::class.simpleName) { updateDeviceList() }
|
|
||||||
}
|
|
||||||
updateDeviceList()
|
updateDeviceList()
|
||||||
onBackPressedDispatcher.addCallback(mainFragmentCallback)
|
onBackPressedDispatcher.addCallback(mainFragmentCallback)
|
||||||
onBackPressedDispatcher.addCallback(closeDrawerCallback)
|
onBackPressedDispatcher.addCallback(closeDrawerCallback)
|
||||||
@ -274,10 +269,10 @@ class MainActivity : AppCompatActivity(), OnSharedPreferenceChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
BackgroundService.RunCommand(this) { service: BackgroundService -> service.removeDeviceListChangedCallback(this::class.simpleName) }
|
KdeConnect.getInstance().removeDeviceListChangedCallback(this::class.simpleName)
|
||||||
super.onStop()
|
|
||||||
mainFragmentCallback.remove()
|
mainFragmentCallback.remove()
|
||||||
closeDrawerCallback.remove()
|
closeDrawerCallback.remove()
|
||||||
|
super.onStop()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
@ -315,11 +310,9 @@ class MainActivity : AppCompatActivity(), OnSharedPreferenceChangeListener {
|
|||||||
@Deprecated("Deprecated in Java")
|
@Deprecated("Deprecated in Java")
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
when {
|
when {
|
||||||
requestCode == RESULT_NEEDS_RELOAD -> BackgroundService.RunCommand(this) { service: BackgroundService ->
|
requestCode == RESULT_NEEDS_RELOAD -> {
|
||||||
val device = service.getDevice(mCurrentDevice)
|
KdeConnect.getInstance().getDevice(mCurrentDevice)?.reloadPluginsFromSettings()
|
||||||
device.reloadPluginsFromSettings()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
requestCode == STORAGE_LOCATION_CONFIGURED && resultCode == RESULT_OK && data != null -> {
|
requestCode == STORAGE_LOCATION_CONFIGURED && resultCode == RESULT_OK && data != null -> {
|
||||||
val uri = data.data
|
val uri = data.data
|
||||||
ShareSettingsFragment.saveStorageLocationPreference(this, uri)
|
ShareSettingsFragment.saveStorageLocationPreference(this, uri)
|
||||||
@ -344,17 +337,14 @@ class MainActivity : AppCompatActivity(), OnSharedPreferenceChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//New permission granted, reload plugins
|
//New permission granted, reload plugins
|
||||||
BackgroundService.RunCommand(this) { service: BackgroundService ->
|
KdeConnect.getInstance().getDevice(mCurrentDevice)?.reloadPluginsFromSettings()
|
||||||
val device = service.getDevice(mCurrentDevice)
|
|
||||||
device.reloadPluginsFromSettings()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
||||||
if (DeviceHelper.KEY_DEVICE_NAME_PREFERENCE == key) {
|
if (DeviceHelper.KEY_DEVICE_NAME_PREFERENCE == key) {
|
||||||
mNavViewDeviceName.text = DeviceHelper.getDeviceName(this)
|
mNavViewDeviceName.text = DeviceHelper.getDeviceName(this)
|
||||||
BackgroundService.RunCommand(this) { obj: BackgroundService -> obj.onNetworkChange() } //Re-send our identity packet
|
BackgroundService.ForceRefreshConnections(this) //Re-send our identity packet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ import androidx.fragment.app.Fragment;
|
|||||||
import org.kde.kdeconnect.BackgroundService;
|
import org.kde.kdeconnect.BackgroundService;
|
||||||
import org.kde.kdeconnect.Device;
|
import org.kde.kdeconnect.Device;
|
||||||
import org.kde.kdeconnect.Helpers.TrustedNetworkHelper;
|
import org.kde.kdeconnect.Helpers.TrustedNetworkHelper;
|
||||||
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect.UserInterface.List.ListAdapter;
|
import org.kde.kdeconnect.UserInterface.List.ListAdapter;
|
||||||
import org.kde.kdeconnect.UserInterface.List.PairingDeviceItem;
|
import org.kde.kdeconnect.UserInterface.List.PairingDeviceItem;
|
||||||
import org.kde.kdeconnect.UserInterface.List.SectionItem;
|
import org.kde.kdeconnect.UserInterface.List.SectionItem;
|
||||||
@ -59,7 +60,6 @@ public class PairingFragment extends Fragment implements PairingDeviceItem.Callb
|
|||||||
private TextView headerText;
|
private TextView headerText;
|
||||||
private TextView noWifiHeader;
|
private TextView noWifiHeader;
|
||||||
private TextView notTrustedText;
|
private TextView notTrustedText;
|
||||||
private boolean isConnectedToNonCellularNetwork = true;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||||
@ -73,7 +73,7 @@ public class PairingFragment extends Fragment implements PairingDeviceItem.Callb
|
|||||||
pairingExplanationTextBinding = PairingExplanationTextBinding.inflate(inflater);
|
pairingExplanationTextBinding = PairingExplanationTextBinding.inflate(inflater);
|
||||||
pairingExplanationTextNoWifiBinding = PairingExplanationTextNoWifiBinding.inflate(inflater);
|
pairingExplanationTextNoWifiBinding = PairingExplanationTextNoWifiBinding.inflate(inflater);
|
||||||
|
|
||||||
devicesListBinding.refreshListLayout.setOnRefreshListener(this::updateDeviceListAction);
|
devicesListBinding.refreshListLayout.setOnRefreshListener(this::refreshDevicesAction);
|
||||||
|
|
||||||
notTrustedText = pairingExplanationNotTrustedBinding.getRoot();
|
notTrustedText = pairingExplanationNotTrustedBinding.getRoot();
|
||||||
notTrustedText.setOnClickListener(null);
|
notTrustedText.setOnClickListener(null);
|
||||||
@ -105,24 +105,18 @@ public class PairingFragment extends Fragment implements PairingDeviceItem.Callb
|
|||||||
mActivity = ((MainActivity) getActivity());
|
mActivity = ((MainActivity) getActivity());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateDeviceListAction() {
|
private void refreshDevicesAction() {
|
||||||
updateDeviceList();
|
BackgroundService.ForceRefreshConnections(requireContext());
|
||||||
BackgroundService.RunCommand(mActivity, BackgroundService::onNetworkChange);
|
|
||||||
devicesListBinding.refreshListLayout.setRefreshing(true);
|
devicesListBinding.refreshListLayout.setRefreshing(true);
|
||||||
|
|
||||||
devicesListBinding.refreshListLayout.postDelayed(() -> {
|
devicesListBinding.refreshListLayout.postDelayed(() -> {
|
||||||
// the view might be destroyed by now
|
if (devicesListBinding != null) { // the view might be destroyed by now
|
||||||
if (devicesListBinding == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
devicesListBinding.refreshListLayout.setRefreshing(false);
|
devicesListBinding.refreshListLayout.setRefreshing(false);
|
||||||
|
}
|
||||||
}, 1500);
|
}, 1500);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateDeviceList() {
|
private void updateDeviceList() {
|
||||||
BackgroundService.RunCommand(mActivity, service -> mActivity.runOnUiThread(() -> {
|
|
||||||
|
|
||||||
if (!isAdded()) {
|
if (!isAdded()) {
|
||||||
//Fragment is not attached to an activity. We will crash if we try to do anything here.
|
//Fragment is not attached to an activity. We will crash if we try to do anything here.
|
||||||
return;
|
return;
|
||||||
@ -136,27 +130,12 @@ public class PairingFragment extends Fragment implements PairingDeviceItem.Callb
|
|||||||
}
|
}
|
||||||
listRefreshCalledThisFrame = true;
|
listRefreshCalledThisFrame = true;
|
||||||
|
|
||||||
Collection<Device> devices = service.getDevices().values();
|
|
||||||
boolean someDevicesReachable = false;
|
|
||||||
for (Device device : devices) {
|
|
||||||
if (device.isReachable()) {
|
|
||||||
someDevicesReachable = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
devicesListBinding.devicesList.removeHeaderView(headerText);
|
|
||||||
devicesListBinding.devicesList.removeHeaderView(noWifiHeader);
|
|
||||||
devicesListBinding.devicesList.removeHeaderView(notTrustedText);
|
|
||||||
|
|
||||||
//Check if we're on Wi-Fi/Local network. If we still see a device, don't do anything special
|
//Check if we're on Wi-Fi/Local network. If we still see a device, don't do anything special
|
||||||
if (someDevicesReachable || isConnectedToNonCellularNetwork) {
|
BackgroundService service = BackgroundService.getInstance();
|
||||||
if (TrustedNetworkHelper.isTrustedNetwork(getContext())) {
|
if (service == null) {
|
||||||
devicesListBinding.devicesList.addHeaderView(headerText);
|
updateConnectivityInfoHeader(true);
|
||||||
} else {
|
} else {
|
||||||
devicesListBinding.devicesList.addHeaderView(notTrustedText);
|
service.isConnectedToNonCellularNetwork().observe(this, this::updateConnectivityInfoHeader);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
devicesListBinding.devicesList.addHeaderView(noWifiHeader);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -167,6 +146,8 @@ public class PairingFragment extends Fragment implements PairingDeviceItem.Callb
|
|||||||
|
|
||||||
connectedSection = new SectionItem(res.getString(R.string.category_connected_devices));
|
connectedSection = new SectionItem(res.getString(R.string.category_connected_devices));
|
||||||
items.add(connectedSection);
|
items.add(connectedSection);
|
||||||
|
|
||||||
|
Collection<Device> devices = KdeConnect.getInstance().getDevices().values();
|
||||||
for (Device device : devices) {
|
for (Device device : devices) {
|
||||||
if (device.isReachable() && device.isPaired()) {
|
if (device.isReachable() && device.isPaired()) {
|
||||||
items.add(new PairingDeviceItem(device, PairingFragment.this));
|
items.add(new PairingDeviceItem(device, PairingFragment.this));
|
||||||
@ -215,26 +196,43 @@ public class PairingFragment extends Fragment implements PairingDeviceItem.Callb
|
|||||||
} finally {
|
} finally {
|
||||||
listRefreshCalledThisFrame = false;
|
listRefreshCalledThisFrame = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateConnectivityInfoHeader(boolean isConnectedToNonCellularNetwork) {
|
||||||
|
Collection<Device> devices = KdeConnect.getInstance().getDevices().values();
|
||||||
|
boolean someDevicesReachable = false;
|
||||||
|
for (Device device : devices) {
|
||||||
|
if (device.isReachable()) {
|
||||||
|
someDevicesReachable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
devicesListBinding.devicesList.removeHeaderView(headerText);
|
||||||
|
devicesListBinding.devicesList.removeHeaderView(noWifiHeader);
|
||||||
|
devicesListBinding.devicesList.removeHeaderView(notTrustedText);
|
||||||
|
|
||||||
|
if (someDevicesReachable || isConnectedToNonCellularNetwork) {
|
||||||
|
if (TrustedNetworkHelper.isTrustedNetwork(getContext())) {
|
||||||
|
devicesListBinding.devicesList.addHeaderView(headerText);
|
||||||
|
} else {
|
||||||
|
devicesListBinding.devicesList.addHeaderView(notTrustedText);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
devicesListBinding.devicesList.addHeaderView(noWifiHeader);
|
||||||
|
}
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
devicesListBinding.refreshListLayout.setEnabled(true);
|
KdeConnect.getInstance().addDeviceListChangedCallback("PairingFragment", () -> mActivity.runOnUiThread(this::updateDeviceList));
|
||||||
BackgroundService.RunCommand(mActivity, service -> service.addDeviceListChangedCallback("PairingFragment", newIsConnectedToNonCellularNetwork -> {
|
BackgroundService.ForceRefreshConnections(requireContext()); // force a network re-discover
|
||||||
isConnectedToNonCellularNetwork = newIsConnectedToNonCellularNetwork;
|
|
||||||
updateDeviceList();
|
|
||||||
}));
|
|
||||||
updateDeviceList();
|
updateDeviceList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
|
KdeConnect.getInstance().removeDeviceListChangedCallback("PairingFragment");
|
||||||
super.onStop();
|
super.onStop();
|
||||||
devicesListBinding.refreshListLayout.setEnabled(false);
|
|
||||||
BackgroundService.RunCommand(mActivity, service -> service.removeDeviceListChangedCallback("PairingFragment"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -265,7 +263,7 @@ public class PairingFragment extends Fragment implements PairingDeviceItem.Callb
|
|||||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||||
int id = item.getItemId();
|
int id = item.getItemId();
|
||||||
if (id == R.id.menu_refresh) {
|
if (id == R.id.menu_refresh) {
|
||||||
updateDeviceListAction();
|
refreshDevicesAction();
|
||||||
return true;
|
return true;
|
||||||
} else if (id == R.id.menu_custom_device_list) {
|
} else if (id == R.id.menu_custom_device_list) {
|
||||||
startActivity(new Intent(mActivity, CustomDevicesActivity.class));
|
startActivity(new Intent(mActivity, CustomDevicesActivity.class));
|
||||||
|
@ -13,8 +13,8 @@ import androidx.appcompat.app.AppCompatActivity;
|
|||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
|
||||||
import org.kde.kdeconnect.Device;
|
import org.kde.kdeconnect.Device;
|
||||||
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect.Plugins.Plugin;
|
import org.kde.kdeconnect.Plugins.Plugin;
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ public class PluginSettingsActivity
|
|||||||
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragmentPlaceHolder);
|
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragmentPlaceHolder);
|
||||||
if (fragment == null) {
|
if (fragment == null) {
|
||||||
if (pluginKey != null) {
|
if (pluginKey != null) {
|
||||||
Device device = BackgroundService.getInstance().getDevice(deviceId);
|
Device device = KdeConnect.getInstance().getDevice(deviceId);
|
||||||
if (device != null) {
|
if (device != null) {
|
||||||
Plugin plugin = device.getPluginIncludingWithoutPermissions(pluginKey);
|
Plugin plugin = device.getPluginIncludingWithoutPermissions(pluginKey);
|
||||||
if (plugin != null) {
|
if (plugin != null) {
|
||||||
|
@ -13,8 +13,8 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.preference.PreferenceFragmentCompat;
|
import androidx.preference.PreferenceFragmentCompat;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
|
||||||
import org.kde.kdeconnect.Device;
|
import org.kde.kdeconnect.Device;
|
||||||
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect.Plugins.Plugin;
|
import org.kde.kdeconnect.Plugins.Plugin;
|
||||||
import org.kde.kdeconnect.Plugins.PluginFactory;
|
import org.kde.kdeconnect.Plugins.PluginFactory;
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
@ -56,7 +56,7 @@ public class PluginSettingsFragment extends PreferenceFragmentCompat {
|
|||||||
|
|
||||||
this.pluginKey = getArguments().getString(ARG_PLUGIN_KEY);
|
this.pluginKey = getArguments().getString(ARG_PLUGIN_KEY);
|
||||||
this.layout = getArguments().getInt(ARG_LAYOUT);
|
this.layout = getArguments().getInt(ARG_LAYOUT);
|
||||||
this.device = getDeviceOrThrow(getDeviceId());
|
this.device = KdeConnect.getInstance().getDevice(getDeviceId());
|
||||||
this.plugin = device.getPluginIncludingWithoutPermissions(pluginKey);
|
this.plugin = device.getPluginIncludingWithoutPermissions(pluginKey);
|
||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@ -85,13 +85,4 @@ public class PluginSettingsFragment extends PreferenceFragmentCompat {
|
|||||||
return ((PluginSettingsActivity)requireActivity()).getDeviceId();
|
return ((PluginSettingsActivity)requireActivity()).getDeviceId();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Device getDeviceOrThrow(String deviceId) {
|
|
||||||
Device device = BackgroundService.getInstance().getDevice(deviceId);
|
|
||||||
|
|
||||||
if (device == null) {
|
|
||||||
throw new RuntimeException("PluginSettingsFragment.onCreatePreferences() - No device with id " + getDeviceId());
|
|
||||||
}
|
|
||||||
|
|
||||||
return device;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,8 @@ import androidx.preference.PreferenceFragmentCompat;
|
|||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
|
||||||
import org.kde.kdeconnect.Device;
|
import org.kde.kdeconnect.Device;
|
||||||
|
import org.kde.kdeconnect.KdeConnect;
|
||||||
import org.kde.kdeconnect.Plugins.PluginFactory;
|
import org.kde.kdeconnect.Plugins.PluginFactory;
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
|
|
||||||
@ -77,8 +77,7 @@ public class PluginSettingsListFragment extends PreferenceFragmentCompat {
|
|||||||
|
|
||||||
final String deviceId = getArguments().getString(ARG_DEVICE_ID);
|
final String deviceId = getArguments().getString(ARG_DEVICE_ID);
|
||||||
|
|
||||||
BackgroundService.RunCommand(requireContext(), service -> {
|
Device device = KdeConnect.getInstance().getDevice(deviceId);
|
||||||
final Device device = service.getDevice(deviceId);
|
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
final FragmentActivity activity = requireActivity();
|
final FragmentActivity activity = requireActivity();
|
||||||
activity.runOnUiThread(activity::finish);
|
activity.runOnUiThread(activity::finish);
|
||||||
@ -92,7 +91,6 @@ public class PluginSettingsListFragment extends PreferenceFragmentCompat {
|
|||||||
PluginPreference pref = new PluginPreference(requireContext(), pluginKey, device, callback);
|
PluginPreference pref = new PluginPreference(requireContext(), pluginKey, device, callback);
|
||||||
preferenceScreen.addPreference(pref);
|
preferenceScreen.addPreference(pref);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -125,8 +125,10 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
|||||||
final boolean isChecked = (Boolean) newValue;
|
final boolean isChecked = (Boolean) newValue;
|
||||||
|
|
||||||
NotificationHelper.setPersistentNotificationEnabled(context, isChecked);
|
NotificationHelper.setPersistentNotificationEnabled(context, isChecked);
|
||||||
BackgroundService.RunCommand(context,
|
BackgroundService service = BackgroundService.getInstance();
|
||||||
service -> service.changePersistentNotificationVisibility(isChecked));
|
if (service != null) {
|
||||||
|
service.changePersistentNotificationVisibility(isChecked);
|
||||||
|
}
|
||||||
|
|
||||||
NotificationHelper.setPersistentNotificationEnabled(context, isChecked);
|
NotificationHelper.setPersistentNotificationEnabled(context, isChecked);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user