mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-08-31 06:05:12 +00:00
Revert "Failed mega refactor"
This reverts commit 8201b8cbdf028cc8946f4e6a8127a316b8cf1339.
This commit is contained in:
@@ -31,7 +31,7 @@ import java.util.ArrayList;
|
|||||||
import androidx.annotation.WorkerThread;
|
import androidx.annotation.WorkerThread;
|
||||||
|
|
||||||
|
|
||||||
public abstract class DeviceLink {
|
public abstract class BaseLink {
|
||||||
|
|
||||||
protected final Context context;
|
protected final Context context;
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ public abstract class DeviceLink {
|
|||||||
private final ArrayList<PacketReceiver> receivers = new ArrayList<>();
|
private final ArrayList<PacketReceiver> receivers = new ArrayList<>();
|
||||||
protected PrivateKey privateKey;
|
protected PrivateKey privateKey;
|
||||||
|
|
||||||
protected DeviceLink(Context context, String deviceId, BaseLinkProvider linkProvider) {
|
protected BaseLink(Context context, String deviceId, BaseLinkProvider linkProvider) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.linkProvider = linkProvider;
|
this.linkProvider = linkProvider;
|
||||||
this.deviceId = deviceId;
|
this.deviceId = deviceId;
|
||||||
@@ -62,6 +62,15 @@ public abstract class DeviceLink {
|
|||||||
privateKey = key;
|
privateKey = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BaseLinkProvider getLinkProvider() {
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
@@ -77,7 +86,7 @@ public abstract class DeviceLink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void disconnect() {
|
public void disconnect() {
|
||||||
linkProvider.onLinkDisconnected(this);
|
linkProvider.connectionLost(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TO OVERRIDE, should be sync
|
//TO OVERRIDE, should be sync
|
@@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
package org.kde.kdeconnect.Backends;
|
package org.kde.kdeconnect.Backends;
|
||||||
|
|
||||||
|
import org.kde.kdeconnect.NetworkPacket;
|
||||||
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
public abstract class BaseLinkProvider {
|
public abstract class BaseLinkProvider {
|
||||||
@@ -27,47 +29,38 @@ public abstract class BaseLinkProvider {
|
|||||||
private final CopyOnWriteArrayList<ConnectionReceiver> connectionReceivers = new CopyOnWriteArrayList<>();
|
private final CopyOnWriteArrayList<ConnectionReceiver> connectionReceivers = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
public interface ConnectionReceiver {
|
public interface ConnectionReceiver {
|
||||||
void onOfferAdded(DeviceOffer offer);
|
void onConnectionReceived(NetworkPacket identityPacket, BaseLink link);
|
||||||
void onOfferRemoved(String id);
|
void onConnectionLost(BaseLink link);
|
||||||
void onLinkConnected(DeviceOffer offer, DeviceLink link);
|
|
||||||
void onConnectionFailed(DeviceOffer offer, String reason);
|
|
||||||
void onLinkDisconnected(DeviceLink link);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addConnectionReceiver(ConnectionReceiver cr) {
|
public void addConnectionReceiver(ConnectionReceiver cr) {
|
||||||
connectionReceivers.add(cr);
|
connectionReceivers.add(cr);
|
||||||
}
|
}
|
||||||
public boolean removeConnectionReceiver(ConnectionReceiver cr) { return connectionReceivers.remove(cr); }
|
|
||||||
|
|
||||||
protected void onOfferAdded(DeviceOffer offer) {
|
public boolean removeConnectionReceiver(ConnectionReceiver cr) {
|
||||||
for(ConnectionReceiver cr : connectionReceivers) {
|
return connectionReceivers.remove(cr);
|
||||||
cr.onOfferAdded(offer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
protected void onOfferRemoved(String id) {
|
|
||||||
for(ConnectionReceiver cr : connectionReceivers) {
|
|
||||||
cr.onOfferRemoved(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onLinkConnected(DeviceOffer offer, DeviceLink link) {
|
//These two should be called when the provider links to a new computer
|
||||||
|
protected void connectionAccepted(NetworkPacket identityPacket, BaseLink link) {
|
||||||
|
//Log.i("KDE/LinkProvider", "connectionAccepted");
|
||||||
for(ConnectionReceiver cr : connectionReceivers) {
|
for(ConnectionReceiver cr : connectionReceivers) {
|
||||||
cr.onLinkConnected(offer, link);
|
cr.onConnectionReceived(identityPacket, link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
protected void onConnectionFailed(DeviceOffer offer, String reason) {
|
protected void connectionLost(BaseLink link) {
|
||||||
|
//Log.i("KDE/LinkProvider", "connectionLost");
|
||||||
for(ConnectionReceiver cr : connectionReceivers) {
|
for(ConnectionReceiver cr : connectionReceivers) {
|
||||||
cr.onConnectionFailed(offer, reason);
|
cr.onConnectionLost(link);
|
||||||
}
|
|
||||||
}
|
|
||||||
protected void onLinkDisconnected(DeviceLink link) {
|
|
||||||
for(ConnectionReceiver cr : connectionReceivers) {
|
|
||||||
cr.onLinkDisconnected(link);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//To override
|
//To override
|
||||||
public abstract void refresh();
|
public abstract void onStart();
|
||||||
|
public abstract void onStop();
|
||||||
|
public abstract void onNetworkChange();
|
||||||
|
|
||||||
|
//public abstract int getPriority();
|
||||||
public abstract String getName();
|
public abstract String getName();
|
||||||
public abstract void connect(DeviceOffer id);
|
|
||||||
}
|
}
|
||||||
|
@@ -20,13 +20,17 @@
|
|||||||
|
|
||||||
package org.kde.kdeconnect.Backends.BluetoothBackend;
|
package org.kde.kdeconnect.Backends.BluetoothBackend;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.bluetooth.BluetoothServerSocket;
|
||||||
|
import android.bluetooth.BluetoothSocket;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.kde.kdeconnect.Backends.DeviceLink;
|
import org.kde.kdeconnect.Backends.BaseLink;
|
||||||
import org.kde.kdeconnect.Backends.BasePairingHandler;
|
import org.kde.kdeconnect.Backends.BasePairingHandler;
|
||||||
import org.kde.kdeconnect.Device;
|
import org.kde.kdeconnect.Device;
|
||||||
import org.kde.kdeconnect.NetworkPacket;
|
import org.kde.kdeconnect.NetworkPacket;
|
||||||
@@ -41,7 +45,7 @@ import java.util.UUID;
|
|||||||
|
|
||||||
import androidx.annotation.WorkerThread;
|
import androidx.annotation.WorkerThread;
|
||||||
|
|
||||||
public class BluetoothLink extends DeviceLink {
|
public class BluetoothLink extends BaseLink {
|
||||||
private final ConnectionMultiplexer connection;
|
private final ConnectionMultiplexer connection;
|
||||||
private final InputStream input;
|
private final InputStream input;
|
||||||
private final OutputStream output;
|
private final OutputStream output;
|
||||||
@@ -199,6 +203,10 @@ public class BluetoothLink extends DeviceLink {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean linkShouldBeKeptAlive() {
|
||||||
|
return receivingThread.isAlive();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
public boolean isConnected() {
|
public boolean isConnected() {
|
||||||
|
@@ -35,7 +35,6 @@ import android.util.Log;
|
|||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
||||||
import org.kde.kdeconnect.Backends.DeviceOffer;
|
|
||||||
import org.kde.kdeconnect.Device;
|
import org.kde.kdeconnect.Device;
|
||||||
import org.kde.kdeconnect.NetworkPacket;
|
import org.kde.kdeconnect.NetworkPacket;
|
||||||
|
|
||||||
@@ -73,9 +72,7 @@ public class BluetoothLinkProvider extends BaseLinkProvider {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
visibleComputers.put(deviceId, link);
|
visibleComputers.put(deviceId, link);
|
||||||
|
connectionAccepted(identityPacket, link);
|
||||||
onLinkConnected(DeviceOffer.FromLegacyIdentityPacket(identityPacket), link);
|
|
||||||
|
|
||||||
link.startListening();
|
link.startListening();
|
||||||
if (oldLink != null) {
|
if (oldLink != null) {
|
||||||
Log.i("BluetoothLinkProvider", "Removing old connection to same device");
|
Log.i("BluetoothLinkProvider", "Removing old connection to same device");
|
||||||
@@ -92,6 +89,7 @@ public class BluetoothLinkProvider extends BaseLinkProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
if (bluetoothAdapter == null) {
|
if (bluetoothAdapter == null) {
|
||||||
return;
|
return;
|
||||||
@@ -115,11 +113,13 @@ public class BluetoothLinkProvider extends BaseLinkProvider {
|
|||||||
new Thread(serverRunnable).start();
|
new Thread(serverRunnable).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refresh() {
|
@Override
|
||||||
|
public void onNetworkChange() {
|
||||||
onStop();
|
onStop();
|
||||||
onStart();
|
onStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
if (bluetoothAdapter == null || clientRunnable == null || serverRunnable == null) {
|
if (bluetoothAdapter == null || clientRunnable == null || serverRunnable == null) {
|
||||||
return;
|
return;
|
||||||
@@ -129,19 +129,15 @@ public class BluetoothLinkProvider extends BaseLinkProvider {
|
|||||||
serverRunnable.stopProcessing();
|
serverRunnable.stopProcessing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "BluetoothLinkProvider";
|
return "BluetoothLinkProvider";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void connect(DeviceOffer id) {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
public void disconnectedLink(BluetoothLink link, String deviceId, BluetoothDevice remoteAddress) {
|
public void disconnectedLink(BluetoothLink link, String deviceId, BluetoothDevice remoteAddress) {
|
||||||
sockets.remove(remoteAddress);
|
sockets.remove(remoteAddress);
|
||||||
visibleComputers.remove(deviceId);
|
visibleComputers.remove(deviceId);
|
||||||
onLinkDisconnected(link);
|
connectionLost(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ServerRunnable implements Runnable {
|
private class ServerRunnable implements Runnable {
|
||||||
|
@@ -1,59 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2014 Albert Vaca Cintora <albertvaka@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License as
|
|
||||||
* published by the Free Software Foundation; either version 2 of
|
|
||||||
* the License or (at your option) version 3 or any later version
|
|
||||||
* accepted by the membership of KDE e.V. (or its successor approved
|
|
||||||
* by the membership of KDE e.V.), which shall act as a proxy
|
|
||||||
* defined in Section 14 of version 3 of the license.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.kde.kdeconnect.Backends;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import org.kde.kdeconnect.Device;
|
|
||||||
import org.kde.kdeconnect.NetworkPacket;
|
|
||||||
|
|
||||||
import java.net.InetAddress;
|
|
||||||
|
|
||||||
|
|
||||||
public class DeviceOffer {
|
|
||||||
|
|
||||||
public String id;
|
|
||||||
public String name;
|
|
||||||
public Device.DeviceType type;
|
|
||||||
public int protocolVersion;
|
|
||||||
|
|
||||||
public InetAddress host;
|
|
||||||
public int port;
|
|
||||||
|
|
||||||
public static DeviceOffer FromLegacyIdentityPacket(NetworkPacket identityPacket) {
|
|
||||||
DeviceOffer ret = new DeviceOffer();
|
|
||||||
ret.id = identityPacket.getString("deviceId");
|
|
||||||
ret.protocolVersion = identityPacket.getInt("protocolVersion");
|
|
||||||
ret.name = identityPacket.getString("deviceName");
|
|
||||||
ret.type = Device.DeviceType.FromString(identityPacket.getString("deviceType", "desktop"));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BaseLinkProvider provider = null;
|
|
||||||
public void connect() {
|
|
||||||
if (provider == null) {
|
|
||||||
Log.e("AAA", "ERROR: Can't connect, provider unknown");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
provider.connect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -24,7 +24,7 @@ import android.content.Context;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.kde.kdeconnect.Backends.DeviceLink;
|
import org.kde.kdeconnect.Backends.BaseLink;
|
||||||
import org.kde.kdeconnect.Backends.BasePairingHandler;
|
import org.kde.kdeconnect.Backends.BasePairingHandler;
|
||||||
import org.kde.kdeconnect.Device;
|
import org.kde.kdeconnect.Device;
|
||||||
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
|
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
|
||||||
@@ -47,7 +47,7 @@ import javax.net.ssl.SSLSocket;
|
|||||||
|
|
||||||
import androidx.annotation.WorkerThread;
|
import androidx.annotation.WorkerThread;
|
||||||
|
|
||||||
public class LanLink extends DeviceLink {
|
public class LanLink extends BaseLink {
|
||||||
|
|
||||||
public interface LinkDisconnectedCallback {
|
public interface LinkDisconnectedCallback {
|
||||||
void linkDisconnected(LanLink brokenLink);
|
void linkDisconnected(LanLink brokenLink);
|
||||||
@@ -260,4 +260,15 @@ public class LanLink extends DeviceLink {
|
|||||||
|
|
||||||
packageReceived(np);
|
packageReceived(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);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -26,9 +26,8 @@ import android.preference.PreferenceManager;
|
|||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.kde.kdeconnect.Backends.DeviceLink;
|
import org.kde.kdeconnect.Backends.BaseLink;
|
||||||
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
||||||
import org.kde.kdeconnect.Backends.DeviceOffer;
|
|
||||||
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;
|
||||||
@@ -90,7 +89,7 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
|
|||||||
public void linkDisconnected(LanLink brokenLink) {
|
public void linkDisconnected(LanLink brokenLink) {
|
||||||
String deviceId = brokenLink.getDeviceId();
|
String deviceId = brokenLink.getDeviceId();
|
||||||
visibleComputers.remove(deviceId);
|
visibleComputers.remove(deviceId);
|
||||||
onLinkDisconnected(brokenLink);
|
connectionLost(brokenLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
//They received my UDP broadcast and are connecting to me. The first thing they sned should be their identity.
|
//They received my UDP broadcast and are connecting to me. The first thing they sned should be their identity.
|
||||||
@@ -165,7 +164,7 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
|
|||||||
}, 5 * 1000);
|
}, 5 * 1000);
|
||||||
|
|
||||||
// Try to cause a reverse connection
|
// Try to cause a reverse connection
|
||||||
refresh();
|
onNetworkChange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -263,7 +262,7 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
|
|||||||
* link is operated on at a time.
|
* link is operated on at a time.
|
||||||
* <p>
|
* <p>
|
||||||
* Without synchronization, the call to {@link SslHelper#parseCertificate(byte[])} in
|
* Without synchronization, the call to {@link SslHelper#parseCertificate(byte[])} in
|
||||||
* {@link Device#addLink(NetworkPacket, DeviceLink)} crashes on some devices running Oreo 8.1 (SDK level 27).
|
* {@link Device#addLink(NetworkPacket, BaseLink)} crashes on some devices running Oreo 8.1 (SDK level 27).
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param identityPacket representation of remote device
|
* @param identityPacket representation of remote device
|
||||||
@@ -285,14 +284,12 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
|
|||||||
//Let's create the link
|
//Let's create the link
|
||||||
LanLink link = new LanLink(context, deviceId, this, socket, connectionOrigin);
|
LanLink link = new LanLink(context, deviceId, this, socket, connectionOrigin);
|
||||||
visibleComputers.put(deviceId, link);
|
visibleComputers.put(deviceId, link);
|
||||||
onLinkConnected(DeviceOffer.FromLegacyIdentityPacket(identityPacket), link);
|
connectionAccepted(identityPacket, link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public LanLinkProvider(Context context)
|
public LanLinkProvider(Context context) {
|
||||||
{
|
|
||||||
this.context = context;
|
this.context = context;
|
||||||
onStart();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupUdpListener() {
|
private void setupUdpListener() {
|
||||||
@@ -416,6 +413,7 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
|
|||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
//Log.i("KDE/LanLinkProvider", "onStart");
|
//Log.i("KDE/LanLinkProvider", "onStart");
|
||||||
if (!listening) {
|
if (!listening) {
|
||||||
@@ -430,10 +428,11 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void refresh() {
|
public void onNetworkChange() {
|
||||||
broadcastUdpPacket();
|
broadcastUdpPacket();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
//Log.i("KDE/LanLinkProvider", "onStop");
|
//Log.i("KDE/LanLinkProvider", "onStop");
|
||||||
listening = false;
|
listening = false;
|
||||||
@@ -454,9 +453,4 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
|
|||||||
return "LanLinkProvider";
|
return "LanLinkProvider";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void connect(DeviceOffer offer) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -22,7 +22,7 @@ package org.kde.kdeconnect.Backends.LoopbackBackend;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import org.kde.kdeconnect.Backends.DeviceLink;
|
import org.kde.kdeconnect.Backends.BaseLink;
|
||||||
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
||||||
import org.kde.kdeconnect.Backends.BasePairingHandler;
|
import org.kde.kdeconnect.Backends.BasePairingHandler;
|
||||||
import org.kde.kdeconnect.Device;
|
import org.kde.kdeconnect.Device;
|
||||||
@@ -30,7 +30,7 @@ import org.kde.kdeconnect.NetworkPacket;
|
|||||||
|
|
||||||
import androidx.annotation.WorkerThread;
|
import androidx.annotation.WorkerThread;
|
||||||
|
|
||||||
public class LoopbackLink extends DeviceLink {
|
public class LoopbackLink extends BaseLink {
|
||||||
|
|
||||||
public LoopbackLink(Context context, BaseLinkProvider linkProvider) {
|
public LoopbackLink(Context context, BaseLinkProvider linkProvider) {
|
||||||
super(context, "loopback", linkProvider);
|
super(context, "loopback", linkProvider);
|
||||||
|
@@ -23,9 +23,6 @@ package org.kde.kdeconnect.Backends.LoopbackBackend;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
||||||
import org.kde.kdeconnect.Backends.DeviceOffer;
|
|
||||||
import org.kde.kdeconnect.Device;
|
|
||||||
import org.kde.kdeconnect.Helpers.DeviceHelper;
|
|
||||||
import org.kde.kdeconnect.NetworkPacket;
|
import org.kde.kdeconnect.NetworkPacket;
|
||||||
|
|
||||||
public class LoopbackLinkProvider extends BaseLinkProvider {
|
public class LoopbackLinkProvider extends BaseLinkProvider {
|
||||||
@@ -37,20 +34,25 @@ public class LoopbackLinkProvider extends BaseLinkProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void connect(DeviceOffer offer) {
|
public void onStart() {
|
||||||
onLinkConnected(offer, new LoopbackLink(context, this));
|
onNetworkChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void refresh() {
|
public void onStop() {
|
||||||
DeviceOffer offer = new DeviceOffer();
|
|
||||||
offer.id = DeviceHelper.getDeviceId(context);
|
|
||||||
offer.name = DeviceHelper.getDeviceName(context);
|
|
||||||
offer.type = DeviceHelper.getDeviceType(context);
|
|
||||||
offer.protocolVersion = DeviceHelper.ProtocolVersion;
|
|
||||||
onOfferAdded(offer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNetworkChange() {
|
||||||
|
NetworkPacket np = NetworkPacket.createIdentityPacket(context);
|
||||||
|
connectionAccepted(np, new LoopbackLink(context, this));
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
@Override
|
||||||
|
public int getPriority() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "LoopbackLinkProvider";
|
return "LoopbackLinkProvider";
|
||||||
|
@@ -25,7 +25,7 @@ import android.content.Context;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.kde.kdeconnect.Backends.DeviceLink;
|
import org.kde.kdeconnect.Backends.BaseLink;
|
||||||
import org.kde.kdeconnect.Backends.BasePairingHandler;
|
import org.kde.kdeconnect.Backends.BasePairingHandler;
|
||||||
import org.kde.kdeconnect.Device;
|
import org.kde.kdeconnect.Device;
|
||||||
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
|
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
|
||||||
@@ -45,7 +45,7 @@ import java.nio.channels.NotYetConnectedException;
|
|||||||
|
|
||||||
import javax.net.ssl.SSLSocket;
|
import javax.net.ssl.SSLSocket;
|
||||||
|
|
||||||
public class MulticastLink extends DeviceLink {
|
public class MulticastLink extends BaseLink {
|
||||||
|
|
||||||
static final String LOG_TAG = "MulticastLink";
|
static final String LOG_TAG = "MulticastLink";
|
||||||
|
|
||||||
@@ -57,6 +57,11 @@ public class MulticastLink extends DeviceLink {
|
|||||||
Locally, Remotely
|
Locally, Remotely
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ConnectionStarted connectionSource; // If the other device sent me a broadcast,
|
||||||
|
// I should not close the connection with it
|
||||||
|
// because it's probably trying to find me and
|
||||||
|
// potentially ask for pairing.
|
||||||
|
|
||||||
private volatile SSLSocket socket = null;
|
private volatile SSLSocket socket = null;
|
||||||
|
|
||||||
private final LinkDisconnectedCallback callback;
|
private final LinkDisconnectedCallback callback;
|
||||||
@@ -72,11 +77,13 @@ public class MulticastLink extends DeviceLink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Returns the old socket
|
//Returns the old socket
|
||||||
public SSLSocket reset(final SSLSocket newSocket) throws IOException {
|
public SSLSocket reset(final SSLSocket newSocket, ConnectionStarted connectionSource) throws IOException {
|
||||||
|
|
||||||
SSLSocket oldSocket = socket;
|
SSLSocket oldSocket = socket;
|
||||||
socket = newSocket;
|
socket = newSocket;
|
||||||
|
|
||||||
|
this.connectionSource = connectionSource;
|
||||||
|
|
||||||
if (oldSocket != null) {
|
if (oldSocket != null) {
|
||||||
oldSocket.close(); //This should cancel the readThread
|
oldSocket.close(); //This should cancel the readThread
|
||||||
}
|
}
|
||||||
@@ -115,10 +122,10 @@ public class MulticastLink extends DeviceLink {
|
|||||||
return oldSocket;
|
return oldSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MulticastLink(Context context, String deviceId, MulticastLinkProvider linkProvider, SSLSocket socket) throws IOException {
|
public MulticastLink(Context context, String deviceId, MulticastLinkProvider linkProvider, SSLSocket socket, ConnectionStarted connectionSource) throws IOException {
|
||||||
super(context, deviceId, linkProvider);
|
super(context, deviceId, linkProvider);
|
||||||
callback = linkProvider;
|
callback = linkProvider;
|
||||||
reset(socket);
|
reset(socket, connectionSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -248,4 +255,14 @@ public class MulticastLink extends DeviceLink {
|
|||||||
packageReceived(np);
|
packageReceived(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);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,36 +24,40 @@ package org.kde.kdeconnect.Backends.MulticastBackend;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.net.Network;
|
||||||
import android.net.nsd.NsdManager;
|
import android.net.nsd.NsdManager;
|
||||||
|
import android.net.nsd.NsdManager.RegistrationListener;
|
||||||
import android.net.nsd.NsdManager.ResolveListener;
|
import android.net.nsd.NsdManager.ResolveListener;
|
||||||
import android.net.nsd.NsdServiceInfo;
|
import android.net.nsd.NsdServiceInfo;
|
||||||
import android.net.wifi.WifiInfo;
|
|
||||||
import android.net.wifi.WifiManager;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.util.Base64;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
|
|
||||||
import org.kde.kdeconnect.Backends.DeviceLink;
|
import org.json.JSONException;
|
||||||
|
import org.kde.kdeconnect.Backends.BaseLink;
|
||||||
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
||||||
import org.kde.kdeconnect.Backends.DeviceOffer;
|
|
||||||
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.Helpers.SecurityHelpers.SslHelper;
|
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
|
||||||
import org.kde.kdeconnect.NetworkPacket;
|
import org.kde.kdeconnect.NetworkPacket;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.security.cert.Certificate;
|
import java.security.cert.Certificate;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import javax.net.SocketFactory;
|
||||||
import javax.net.ssl.SSLSocket;
|
import javax.net.ssl.SSLSocket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,13 +69,13 @@ import javax.net.ssl.SSLSocket;
|
|||||||
*/
|
*/
|
||||||
public class MulticastLinkProvider extends BaseLinkProvider implements MulticastLink.LinkDisconnectedCallback {
|
public class MulticastLinkProvider extends BaseLinkProvider implements MulticastLink.LinkDisconnectedCallback {
|
||||||
|
|
||||||
HashMap<InetAddress, DeviceOffer> offers = new HashMap<>();
|
|
||||||
|
|
||||||
static final String LOG_TAG = "MulticastLink";
|
static final String LOG_TAG = "MulticastLink";
|
||||||
|
|
||||||
static final String SERVICE_TYPE = "_kdeconnect._tcp";
|
static final String SERVICE_TYPE = "_kdeconnect._tcp";
|
||||||
|
|
||||||
private NsdManager mNsdManager;
|
private NsdManager mNsdManager;
|
||||||
|
private RegistrationListener mRegistrationListener;
|
||||||
|
private boolean mServiceRegistered = false;
|
||||||
|
|
||||||
private final static int MIN_PORT = 1716;
|
private final static int MIN_PORT = 1716;
|
||||||
private final static int MAX_PORT = 1764;
|
private final static int MAX_PORT = 1764;
|
||||||
@@ -85,31 +89,31 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
|
|||||||
|
|
||||||
private boolean listening = false;
|
private boolean listening = false;
|
||||||
|
|
||||||
|
// To prevent infinte loop between Android < IceCream because both device can only broadcast identity package but cannot connect via TCP
|
||||||
|
private final ArrayList<InetAddress> reverseConnectionBlackList = new ArrayList<>();
|
||||||
|
|
||||||
@Override // SocketClosedCallback
|
@Override // SocketClosedCallback
|
||||||
public void linkDisconnected(MulticastLink brokenLink) {
|
public void linkDisconnected(MulticastLink brokenLink) {
|
||||||
String deviceId = brokenLink.getDeviceId();
|
String deviceId = brokenLink.getDeviceId();
|
||||||
visibleComputers.remove(deviceId);
|
visibleComputers.remove(deviceId);
|
||||||
onLinkDisconnected(brokenLink);
|
connectionLost(brokenLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
private InetAddress getDeviceIpAddress() {
|
// They received my mDNS broadcast and are connecting to me. The first thing they send should be their identity.
|
||||||
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
|
private void tcpPacketReceived(Socket socket) {
|
||||||
WifiManager.MulticastLock lock = wifi.createMulticastLock("jmdns-multicast-lock");
|
|
||||||
lock.setReferenceCounted(true);
|
writeIdentity(socket);
|
||||||
lock.acquire();
|
NetworkPacket otherIdentity = readIdentity(socket);
|
||||||
InetAddress result = null;
|
|
||||||
try {
|
if (!otherIdentity.getType().equals(NetworkPacket.PACKET_TYPE_IDENTITY)) {
|
||||||
// figure out our wifi address, otherwise bail
|
Log.e(LOG_TAG, "Expecting an identity package instead of " + otherIdentity.getType());
|
||||||
WifiInfo wifiinfo = wifi.getConnectionInfo();
|
return;
|
||||||
int intaddr = wifiinfo.getIpAddress();
|
|
||||||
byte[] byteaddr = new byte[] { (byte) (intaddr & 0xff), (byte) (intaddr >> 8 & 0xff),
|
|
||||||
(byte) (intaddr >> 16 & 0xff), (byte) (intaddr >> 24 & 0xff) };
|
|
||||||
return InetAddress.getByAddress(byteaddr);
|
|
||||||
} catch (UnknownHostException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log.i(LOG_TAG, "Identity package received from a TCP connection from " + otherIdentity.getString("deviceName"));
|
||||||
|
identityPacketReceived(otherIdentity, socket, MulticastLink.ConnectionStarted.Locally);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void configureSocket(Socket socket) {
|
private void configureSocket(Socket socket) {
|
||||||
try {
|
try {
|
||||||
socket.setKeepAlive(true);
|
socket.setKeepAlive(true);
|
||||||
@@ -118,34 +122,58 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a socket is connected.
|
* Called when a new 'identity' packet is received. Those are passed here by
|
||||||
|
* {@link #tcpPacketReceived(Socket)}
|
||||||
|
* <p>
|
||||||
|
* If the remote device should be connected, this calls {@link #addLink}.
|
||||||
|
* Otherwise, if there was an Exception, we unpair from that device.
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
|
* @param identityPacket identity of a remote device
|
||||||
* @param socket a new Socket, which should be used to receive packets from the remote device
|
* @param socket a new Socket, which should be used to receive packets from the remote device
|
||||||
* @param connectionStarted which side started this connection
|
* @param connectionStarted which side started this connection
|
||||||
*/
|
*/
|
||||||
private void doTheSslDance(DeviceOffer deviceOffer, final Socket socket, final MulticastLink.ConnectionStarted connectionStarted) {
|
private void identityPacketReceived(final NetworkPacket identityPacket, final Socket socket, final MulticastLink.ConnectionStarted connectionStarted) {
|
||||||
|
|
||||||
String deviceId = deviceOffer.id;
|
String myId = DeviceHelper.getDeviceId(context);
|
||||||
|
final String deviceId = identityPacket.getString("deviceId");
|
||||||
|
if (deviceId.equals(myId)) {
|
||||||
|
Log.e(LOG_TAG, "Somehow I'm connected to myself, ignoring. This should not happen.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If I'm the TCP server I will be the SSL client and viceversa.
|
// If I'm the TCP server I will be the SSL client and viceversa.
|
||||||
final boolean clientMode = (connectionStarted == MulticastLink.ConnectionStarted.Locally);
|
final boolean clientMode = (connectionStarted == MulticastLink.ConnectionStarted.Locally);
|
||||||
|
|
||||||
|
// Do the SSL handshake
|
||||||
try {
|
try {
|
||||||
SharedPreferences preferences = context.getSharedPreferences("trusted_devices", Context.MODE_PRIVATE);
|
SharedPreferences preferences = context.getSharedPreferences("trusted_devices", Context.MODE_PRIVATE);
|
||||||
boolean isDeviceTrusted = preferences.getBoolean(deviceId, false);
|
boolean isDeviceTrusted = preferences.getBoolean(deviceId, false);
|
||||||
|
|
||||||
Log.i(LOG_TAG, "Starting SSL handshake with " + deviceOffer.name + " trusted:" + isDeviceTrusted);
|
if (isDeviceTrusted && !SslHelper.isCertificateStored(context, deviceId)) {
|
||||||
|
//Device paired with and old version, we can't use it as we lack the certificate
|
||||||
|
BackgroundService.RunCommand(context, service -> {
|
||||||
|
Device device = service.getDevice(deviceId);
|
||||||
|
if (device == null) return;
|
||||||
|
device.unpair();
|
||||||
|
//Retry as unpaired
|
||||||
|
identityPacketReceived(identityPacket, socket, connectionStarted);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.i(LOG_TAG, "Starting SSL handshake with " + identityPacket.getString("deviceName") + " trusted:" + isDeviceTrusted);
|
||||||
|
|
||||||
final SSLSocket sslsocket = SslHelper.convertToSslSocket(context, socket, deviceId, isDeviceTrusted, clientMode);
|
final SSLSocket sslsocket = SslHelper.convertToSslSocket(context, socket, deviceId, isDeviceTrusted, clientMode);
|
||||||
sslsocket.addHandshakeCompletedListener(event -> {
|
sslsocket.addHandshakeCompletedListener(event -> {
|
||||||
|
String mode = clientMode ? "client" : "server";
|
||||||
try {
|
try {
|
||||||
Certificate certificate = event.getPeerCertificates()[0];
|
Certificate certificate = event.getPeerCertificates()[0];
|
||||||
createLink(deviceOffer, sslsocket);
|
identityPacket.set("certificate", Base64.encodeToString(certificate.getEncoded(), 0));
|
||||||
|
Log.i(LOG_TAG, "Handshake as " + mode + " successful with " + identityPacket.getString("deviceName") + " secured with " + event.getCipherSuite());
|
||||||
|
addLink(identityPacket, sslsocket, connectionStarted);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
String mode = clientMode ? "client" : "server";
|
Log.e(LOG_TAG, "Handshake as " + mode + " failed with " + identityPacket.getString("deviceName"), e);
|
||||||
Log.e(LOG_TAG, "Handshake as " + mode + " failed with " + deviceOffer.name, e);
|
|
||||||
BackgroundService.RunCommand(context, service -> {
|
BackgroundService.RunCommand(context, service -> {
|
||||||
Device device = service.getDevice(deviceId);
|
Device device = service.getDevice(deviceId);
|
||||||
if (device == null) return;
|
if (device == null) return;
|
||||||
@@ -160,7 +188,7 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
|
|||||||
sslsocket.startHandshake();
|
sslsocket.startHandshake();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(LOG_TAG, "Handshake failed with " + deviceOffer.name, e);
|
Log.e(LOG_TAG, "Handshake failed with " + identityPacket.getString("deviceName"), e);
|
||||||
|
|
||||||
//String[] ciphers = sslsocket.getSupportedCipherSuites();
|
//String[] ciphers = sslsocket.getSupportedCipherSuites();
|
||||||
//for (String cipher : ciphers) {
|
//for (String cipher : ciphers) {
|
||||||
@@ -179,7 +207,7 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
|
|||||||
* link is operated on at a time.
|
* link is operated on at a time.
|
||||||
* <p>
|
* <p>
|
||||||
* Without synchronization, the call to {@link SslHelper#parseCertificate(byte[])} in
|
* Without synchronization, the call to {@link SslHelper#parseCertificate(byte[])} in
|
||||||
* {@link Device#addLink(NetworkPacket, DeviceLink)} crashes on some devices running Oreo 8.1 (SDK level 27).
|
* {@link Device#addLink(NetworkPacket, BaseLink)} crashes on some devices running Oreo 8.1 (SDK level 27).
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param identityPacket representation of remote device
|
* @param identityPacket representation of remote device
|
||||||
@@ -187,50 +215,53 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
|
|||||||
* @param connectionOrigin which side started this connection
|
* @param connectionOrigin which side started this connection
|
||||||
* @throws IOException if an exception is thrown by {@link MulticastLink#reset(SSLSocket, MulticastLink.ConnectionStarted)}
|
* @throws IOException if an exception is thrown by {@link MulticastLink#reset(SSLSocket, MulticastLink.ConnectionStarted)}
|
||||||
*/
|
*/
|
||||||
private void createLink(DeviceOffer offer, SSLSocket socket) throws IOException {
|
private void addLink(final NetworkPacket identityPacket, SSLSocket socket, MulticastLink.ConnectionStarted connectionOrigin) throws IOException {
|
||||||
String deviceId = offer.id;
|
|
||||||
|
String deviceId = identityPacket.getString("deviceId");
|
||||||
MulticastLink currentLink = visibleComputers.get(deviceId);
|
MulticastLink currentLink = visibleComputers.get(deviceId);
|
||||||
if (currentLink != null) {
|
if (currentLink != null) {
|
||||||
//Update old link
|
//Update old link
|
||||||
Log.i(LOG_TAG, "Reusing same link for device " + deviceId);
|
Log.i(LOG_TAG, "Reusing same link for device " + deviceId);
|
||||||
final Socket oldSocket = currentLink.reset(socket);
|
final Socket oldSocket = currentLink.reset(socket, connectionOrigin);
|
||||||
//Log.e(LOG_TAG, "Replacing socket. old: "+ oldSocket.hashCode() + " - new: "+ socket.hashCode());
|
//Log.e(LOG_TAG, "Replacing socket. old: "+ oldSocket.hashCode() + " - new: "+ socket.hashCode());
|
||||||
} else {
|
} else {
|
||||||
Log.i(LOG_TAG, "Creating a new link for device " + deviceId);
|
Log.i(LOG_TAG, "Creating a new link for device " + deviceId);
|
||||||
//Let's create the link
|
//Let's create the link
|
||||||
MulticastLink link = new MulticastLink(context, deviceId, this, socket);
|
MulticastLink link = new MulticastLink(context, deviceId, this, socket, connectionOrigin);
|
||||||
visibleComputers.put(deviceId, link);
|
visibleComputers.put(deviceId, link);
|
||||||
onLinkConnected(offer, link);
|
connectionAccepted(identityPacket, link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private NsdServiceInfo createServiceInfoForTcpServer(InetAddress address, int port) {
|
|
||||||
NsdServiceInfo serviceInfo = new NsdServiceInfo();
|
|
||||||
|
|
||||||
// The name is subject to change based on conflicts
|
|
||||||
// with other services advertised on the same network.
|
|
||||||
String name = DeviceHelper.getDeviceName(context);
|
|
||||||
|
|
||||||
serviceInfo.setAttribute("name", name);
|
|
||||||
serviceInfo.setAttribute("id", DeviceHelper.getDeviceId(context));
|
|
||||||
serviceInfo.setAttribute("type", DeviceHelper.getDeviceType(context).toString());
|
|
||||||
serviceInfo.setAttribute("version", Integer.toString(DeviceHelper.ProtocolVersion));
|
|
||||||
serviceInfo.setAttribute("ip", address.toString());
|
|
||||||
|
|
||||||
|
|
||||||
// It might be nice to add the capabilities in the mDNS advertisement too, but without
|
|
||||||
// some kind of encoding that is too large for the TXT record
|
|
||||||
|
|
||||||
serviceInfo.setServiceName("KDE Connect on " + name);
|
|
||||||
serviceInfo.setServiceType(SERVICE_TYPE);
|
|
||||||
serviceInfo.setPort(port);
|
|
||||||
serviceInfo.setHost(address);
|
|
||||||
|
|
||||||
return serviceInfo;
|
|
||||||
}
|
|
||||||
public MulticastLinkProvider(Context context) {
|
public MulticastLinkProvider(Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
|
}
|
||||||
|
|
||||||
|
private void writeIdentity(Socket socket) {
|
||||||
|
try {
|
||||||
|
OutputStream out = socket.getOutputStream();
|
||||||
|
NetworkPacket myIdentity = NetworkPacket.createIdentityPacket(context);
|
||||||
|
out.write(myIdentity.serialize().getBytes());
|
||||||
|
out.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(LOG_TAG, "Unable to get stream from socket", e);
|
||||||
|
return;
|
||||||
|
} catch (JSONException e) {
|
||||||
|
Log.e(LOG_TAG, "Unable to deserialize JSON", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private NetworkPacket readIdentity(Socket socket) {
|
||||||
|
try {
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
String message = reader.readLine();
|
||||||
|
return NetworkPacket.unserialize(message);
|
||||||
|
//Log.e("TcpListener","Received TCP package: "+networkPacket.serialize());
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(LOG_TAG, "Exception while receiving TCP packet", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupTcpListener() {
|
private void setupTcpListener() {
|
||||||
@@ -245,21 +276,14 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
|
|||||||
try {
|
try {
|
||||||
Socket socket = tcpServer.accept();
|
Socket socket = tcpServer.accept();
|
||||||
configureSocket(socket);
|
configureSocket(socket);
|
||||||
InetAddress remoteAddress = socket.getInetAddress();
|
tcpPacketReceived(socket);
|
||||||
DeviceOffer offer = offers.get(remoteAddress);
|
|
||||||
//if (offer == null) {
|
|
||||||
// Log.e(LOG_TAG, "Received a connection from an unknown device "+ remoteAddress.toString() + ", ignoring!");
|
|
||||||
// socket.close();
|
|
||||||
// return;
|
|
||||||
// //offer = (DeviceOffer)(offers.values().toArray()[0]);
|
|
||||||
//}
|
|
||||||
doTheSslDance(offer, socket, MulticastLink.ConnectionStarted.Remotely);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(LOG_TAG, "TcpReceive exception", e);
|
Log.e(LOG_TAG, "TcpReceive exception", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log.w("TcpListener", "Stopping TCP listener");
|
Log.w("TcpListener", "Stopping TCP listener");
|
||||||
}).start();
|
}).start();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ServerSocket openServerSocketOnFreePort(int minPort) throws IOException {
|
static ServerSocket openServerSocketOnFreePort(int minPort) throws IOException {
|
||||||
@@ -281,37 +305,78 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
|
|||||||
throw new RuntimeException("This should not be reachable");
|
throw new RuntimeException("This should not be reachable");
|
||||||
}
|
}
|
||||||
|
|
||||||
NsdManager.RegistrationListener mRegistrationListener = new NsdManager.RegistrationListener() {
|
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
public void initializeRegistrationListener() {
|
||||||
|
mRegistrationListener = new NsdManager.RegistrationListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) {
|
public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) {
|
||||||
// Save the service name. Android may have changed it in order to
|
// Save the service name. Android may have changed it in order to
|
||||||
// resolve a conflict, so update the name you initially requested
|
// resolve a conflict, so update the name you initially requested
|
||||||
// with the name Android actually used.
|
// with the name Android actually used.
|
||||||
Log.i(LOG_TAG, "Registered " + NsdServiceInfo.getServiceName());
|
Log.i(LOG_TAG, "Registered " + NsdServiceInfo.getServiceName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
|
||||||
|
// Registration failed! Put debugging code here to determine why.
|
||||||
|
Log.e(LOG_TAG, "Registration failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceUnregistered(NsdServiceInfo arg0) {
|
||||||
|
// Service has been unregistered. This only happens when you call
|
||||||
|
// NsdManager.unregisterService() and pass in this listener.
|
||||||
|
Log.w(LOG_TAG, "Service unregistered: " + arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
|
||||||
|
// Unregistration failed. Put debugging code here to determine why.
|
||||||
|
Log.e(LOG_TAG, "Unregister of " + serviceInfo + " failed with: " + errorCode);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
public void initializeNsdManager(RegistrationListener registrationListener) {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
|
||||||
@Override
|
try {
|
||||||
public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
|
mNsdManager.unregisterService(registrationListener);
|
||||||
// Registration failed! Put debugging code here to determine why.
|
} catch (java.lang.IllegalArgumentException e) {
|
||||||
Log.e(LOG_TAG, "Registration failed");
|
// not yet registered, but it's fine.
|
||||||
}
|
}
|
||||||
|
NsdServiceInfo serviceInfo = new NsdServiceInfo();
|
||||||
|
|
||||||
@Override
|
// The name is subject to change based on conflicts
|
||||||
public void onServiceUnregistered(NsdServiceInfo serviceInfo) {
|
// with other services advertised on the same network.
|
||||||
// Service has been unregistered. This only happens when you call
|
NetworkPacket myIdentity = NetworkPacket.createIdentityPacket(context);
|
||||||
// NsdManager.unregisterService() and pass in this listener.
|
String did = myIdentity.getString("deviceID");
|
||||||
|
String name = myIdentity.getString("deviceName");
|
||||||
|
InetAddress addr = this.tcpServer.getInetAddress();
|
||||||
|
int port = this.tcpServer.getLocalPort();
|
||||||
|
|
||||||
Log.e(LOG_TAG, "Service unregistered: " + serviceInfo);
|
// These cause the requirement for api level 21.
|
||||||
offers.remove(serviceInfo.getHost());
|
serviceInfo.setAttribute("name", myIdentity.getString("deviceName"));
|
||||||
}
|
serviceInfo.setAttribute("id", myIdentity.getString("deviceId"));
|
||||||
|
serviceInfo.setAttribute("type", myIdentity.getString("deviceType"));
|
||||||
|
serviceInfo.setAttribute("version", myIdentity.getString("protocolVersion"));
|
||||||
|
|
||||||
@Override
|
// It might be nice to add the capabilities in the mDNS advertisement too, but without
|
||||||
public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
|
// some kind of encoding that is too large for the TXT record
|
||||||
// Unregistration failed. Put debugging code here to determine why.
|
|
||||||
Log.e(LOG_TAG, "Unregister of " + serviceInfo + " failed with: " + errorCode);
|
serviceInfo.setServiceName("KDE Connect on " + myIdentity.getString("deviceName"));
|
||||||
}
|
serviceInfo.setServiceType(SERVICE_TYPE);
|
||||||
};
|
serviceInfo.setHost(addr);
|
||||||
|
serviceInfo.setPort(port);
|
||||||
|
|
||||||
|
//Log.d("KDE/Lan", "service: " + serviceInfo.toString());
|
||||||
|
|
||||||
|
mNsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener);
|
||||||
|
}
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
|
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
|
||||||
public ResolveListener createResolveListener() {
|
public ResolveListener createResolveListener() {
|
||||||
@@ -322,134 +387,120 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
|
|||||||
Log.e(LOG_TAG, "Could not resolve service: " + serviceInfo);
|
Log.e(LOG_TAG, "Could not resolve service: " + serviceInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
String getString(NsdServiceInfo serviceInfo, String key) {
|
@Override
|
||||||
byte[] raw = serviceInfo.getAttributes().get(key);
|
|
||||||
if (raw == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new String(raw, StandardCharsets.UTF_8);
|
|
||||||
}
|
|
||||||
public void onServiceResolved(NsdServiceInfo serviceInfo) {
|
public void onServiceResolved(NsdServiceInfo serviceInfo) {
|
||||||
Log.e(LOG_TAG, "Successfully resolved " + serviceInfo);
|
Log.i(LOG_TAG, "Successfully resolved " + serviceInfo);
|
||||||
|
|
||||||
String id = getString(serviceInfo, "id");
|
|
||||||
if (id == null) {
|
|
||||||
Log.e(LOG_TAG, "Id not found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (id.equals(DeviceHelper.getDeviceId(context))) {
|
|
||||||
Log.e(LOG_TAG, "Ignoring myself " + serviceInfo);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String name = getString(serviceInfo, "name");
|
|
||||||
if (name == null) {
|
|
||||||
Log.e(LOG_TAG, "Name not found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String type_s = getString(serviceInfo, "type");
|
|
||||||
if (type_s == null) {
|
|
||||||
Log.e(LOG_TAG, "Device type not found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Device.DeviceType type = Device.DeviceType.FromString(type_s);
|
|
||||||
|
|
||||||
String version_s = getString(serviceInfo, "version");
|
|
||||||
if (version_s == null) {
|
|
||||||
Log.e(LOG_TAG, "Protocol version not found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int protocolVersion = Integer.parseInt(version_s);
|
|
||||||
|
|
||||||
InetAddress hostname = serviceInfo.getHost();
|
InetAddress hostname = serviceInfo.getHost();
|
||||||
int remotePort = serviceInfo.getPort();
|
int remotePort = serviceInfo.getPort();
|
||||||
|
|
||||||
DeviceOffer offer = new DeviceOffer();
|
SocketFactory socketFactory = SocketFactory.getDefault();
|
||||||
offer.id = id;
|
Socket socket;
|
||||||
offer.name = name;
|
try {
|
||||||
offer.type = type;
|
socket = socketFactory.createSocket(hostname, remotePort);
|
||||||
offer.protocolVersion = protocolVersion;
|
} catch (IOException e) {
|
||||||
offer.host = hostname;
|
Log.e(LOG_TAG, "Unable to open socket to mDNS remote: " + serviceInfo, e);
|
||||||
offer.port = remotePort;
|
return;
|
||||||
offer.provider = MulticastLinkProvider.this;
|
}
|
||||||
|
|
||||||
offers.put(hostname, offer);
|
writeIdentity(socket);
|
||||||
onOfferAdded(offer);
|
NetworkPacket otherIdentity = readIdentity(socket);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Log.i(LOG_TAG, "Got identity: " + otherIdentity.serialize());
|
||||||
|
} catch (JSONException e) {
|
||||||
|
Log.e(LOG_TAG, "Got identity, but unable to serialize!", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
|
||||||
|
public void initializeDiscoveryListener() {
|
||||||
|
// Instantiate a new DiscoveryListener
|
||||||
|
NsdManager.DiscoveryListener discoveryListener = new NsdManager.DiscoveryListener() {
|
||||||
|
|
||||||
NsdManager.DiscoveryListener discoveryListener = new NsdManager.DiscoveryListener() {
|
// Called as soon as service discovery begins.
|
||||||
|
@Override
|
||||||
|
public void onDiscoveryStarted(String regType) {
|
||||||
|
Log.d(LOG_TAG, "Service discovery started");
|
||||||
|
}
|
||||||
|
|
||||||
// Called as soon as service discovery begins.
|
@Override
|
||||||
@Override
|
public void onServiceFound(NsdServiceInfo service) {
|
||||||
public void onDiscoveryStarted(String regType) {
|
// A service was found! Do something with it.
|
||||||
Log.e(LOG_TAG, "Service discovery started");
|
Log.d(LOG_TAG, "Service discovery success" + service);
|
||||||
}
|
mNsdManager.resolveService(service, createResolveListener());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServiceFound(NsdServiceInfo service) {
|
public void onServiceLost(NsdServiceInfo service) {
|
||||||
// A service was found! Do something with it.
|
// When the network service is no longer available.
|
||||||
Log.e(LOG_TAG, "Service discovery success " + service);
|
// Internal bookkeeping code goes here.
|
||||||
mNsdManager.resolveService(service, createResolveListener());
|
Log.e(LOG_TAG, "service lost: " + service);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServiceLost(NsdServiceInfo service) {
|
public void onDiscoveryStopped(String serviceType) {
|
||||||
// When the network service is no longer available.
|
Log.i(LOG_TAG, "Discovery stopped: " + serviceType);
|
||||||
// Internal bookkeeping code goes here.
|
listening = false;
|
||||||
Log.e(LOG_TAG, "service lost: " + service);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDiscoveryStopped(String serviceType) {
|
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
|
||||||
Log.e(LOG_TAG, "Discovery stopped: " + serviceType);
|
Log.e(LOG_TAG, "Discovery failed: Error code:" + errorCode);
|
||||||
listening = false;
|
mNsdManager.stopServiceDiscovery(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
|
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
|
||||||
Log.e(LOG_TAG, "Discovery failed: Error code:" + errorCode);
|
Log.e(LOG_TAG, "Discovery failed: Error code:" + errorCode);
|
||||||
mNsdManager.stopServiceDiscovery(this);
|
mNsdManager.stopServiceDiscovery(this);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener);
|
||||||
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
|
}
|
||||||
Log.e(LOG_TAG, "Discovery failed: Error code:" + errorCode);
|
|
||||||
mNsdManager.stopServiceDiscovery(this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void refresh() {
|
public void onStart() {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
Log.i(LOG_TAG, "MulticastBackend not supported on devices older thab Lollipop");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!listening) {
|
||||||
|
listening = true;
|
||||||
|
|
||||||
|
// Need to set up TCP before setting up mDNS because we need to know the TCP listening
|
||||||
|
// address and port
|
||||||
|
setupTcpListener();
|
||||||
|
|
||||||
|
initializeRegistrationListener();
|
||||||
|
|
||||||
|
initializeNsdManager(mRegistrationListener);
|
||||||
|
|
||||||
|
initializeDiscoveryListener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNetworkChange() {
|
||||||
onStop();
|
onStop();
|
||||||
onStart();
|
onStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void onStart() {
|
@Override
|
||||||
Log.e(LOG_TAG,"ON_START");
|
public void onStop() {
|
||||||
if (!listening) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||||
Log.e(LOG_TAG,"ON_START doing things");
|
// This backend does not work on older Android versions
|
||||||
listening = true;
|
return;
|
||||||
// We set the tcp server port on the service info, so we need to create it beforehand
|
|
||||||
setupTcpListener();
|
|
||||||
NsdServiceInfo serviceInfo = createServiceInfoForTcpServer( getDeviceIpAddress(), this.tcpServer.getLocalPort());
|
|
||||||
mNsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);
|
|
||||||
mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void onStop() {
|
mNsdManager.unregisterService(mRegistrationListener);
|
||||||
/*Log.e(LOG_TAG,"ON_STOP");
|
tcpServer.close();
|
||||||
if (listening) {
|
listening = false;
|
||||||
Log.e(LOG_TAG,"ON_STOP doing things");
|
|
||||||
mNsdManager.stopServiceDiscovery(discoveryListener);
|
|
||||||
mNsdManager.unregisterService(mRegistrationListener);
|
|
||||||
try { tcpServer.close(); } catch (IOException ignore) { }
|
|
||||||
listening = false;
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -457,29 +508,4 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
|
|||||||
return "MulticastLinkProvider";
|
return "MulticastLinkProvider";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void connect(DeviceOffer offer) {
|
|
||||||
try {
|
|
||||||
Socket socket = new Socket(offer.host,offer.port);
|
|
||||||
doTheSslDance(offer, socket, MulticastLink.ConnectionStarted.Locally);
|
|
||||||
} catch (IOException e) {
|
|
||||||
onConnectionFailed(offer, e.getLocalizedMessage());
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
void trustDevice() {
|
|
||||||
if (identityPacket.has("certificate")) {
|
|
||||||
String certificateString = identityPacket.getString("certificate");
|
|
||||||
|
|
||||||
try {
|
|
||||||
byte[] certificateBytes = Base64.decode(certificateString, 0);
|
|
||||||
certificate = SslHelper.parseCertificate(certificateBytes);
|
|
||||||
Log.i("KDE/Device", "Got certificate ");
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e("KDE/Device", "Error getting certificate", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
@@ -39,9 +39,8 @@ 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 org.kde.kdeconnect.Backends.DeviceLink;
|
import org.kde.kdeconnect.Backends.BaseLink;
|
||||||
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
||||||
import org.kde.kdeconnect.Backends.DeviceOffer;
|
|
||||||
import org.kde.kdeconnect.Backends.LanBackend.LanLinkProvider;
|
import org.kde.kdeconnect.Backends.LanBackend.LanLinkProvider;
|
||||||
import org.kde.kdeconnect.Backends.MulticastBackend.MulticastLinkProvider;
|
import org.kde.kdeconnect.Backends.MulticastBackend.MulticastLinkProvider;
|
||||||
import org.kde.kdeconnect.Helpers.NotificationHelper;
|
import org.kde.kdeconnect.Helpers.NotificationHelper;
|
||||||
@@ -84,7 +83,6 @@ public class BackgroundService extends Service {
|
|||||||
private final ArrayList<BaseLinkProvider> linkProviders = new ArrayList<>();
|
private final ArrayList<BaseLinkProvider> linkProviders = new ArrayList<>();
|
||||||
|
|
||||||
private final ConcurrentHashMap<String, Device> devices = new ConcurrentHashMap<>();
|
private final ConcurrentHashMap<String, Device> devices = new ConcurrentHashMap<>();
|
||||||
private final ConcurrentHashMap<String, DeviceOffer> deviceOffers = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private final HashSet<Object> discoveryModeAcquisitions = new HashSet<>();
|
private final HashSet<Object> discoveryModeAcquisitions = new HashSet<>();
|
||||||
|
|
||||||
@@ -102,6 +100,19 @@ public class BackgroundService extends Service {
|
|||||||
return wasEmpty;
|
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() {
|
private final Device.PairingCallback devicePairingCallback = new Device.PairingCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void incomingRequest() {
|
public void incomingRequest() {
|
||||||
@@ -152,7 +163,7 @@ public class BackgroundService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void registerLinkProviders() {
|
private void registerLinkProviders() {
|
||||||
//linkProviders.add(new LanLinkProvider(this));
|
linkProviders.add(new LanLinkProvider(this));
|
||||||
linkProviders.add(new MulticastLinkProvider(this));
|
linkProviders.add(new MulticastLinkProvider(this));
|
||||||
// linkProviders.add(new LoopbackLinkProvider(this));
|
// linkProviders.add(new LoopbackLinkProvider(this));
|
||||||
// linkProviders.add(new BluetoothLinkProvider(this));
|
// linkProviders.add(new BluetoothLinkProvider(this));
|
||||||
@@ -166,55 +177,46 @@ public class BackgroundService extends Service {
|
|||||||
return devices.get(id);
|
return devices.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void cleanDevices() {
|
||||||
|
new Thread(() -> {
|
||||||
|
for (Device d : devices.values()) {
|
||||||
|
if (!d.isPaired() && !d.isPairRequested() && !d.isPairRequestedByPeer() && !d.deviceShouldBeKeptAlive()) {
|
||||||
|
d.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
private final BaseLinkProvider.ConnectionReceiver deviceListener = new BaseLinkProvider.ConnectionReceiver() {
|
private final BaseLinkProvider.ConnectionReceiver deviceListener = new BaseLinkProvider.ConnectionReceiver() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOfferAdded(DeviceOffer offer) {
|
public void onConnectionReceived(final NetworkPacket identityPacket, final BaseLink link) {
|
||||||
deviceOffers.put(offer.id, offer);
|
|
||||||
|
|
||||||
|
String deviceId = identityPacket.getString("deviceId");
|
||||||
|
|
||||||
// TEST
|
|
||||||
Log.e("KDE/BackgroundService", "offer added: " + offer.id);
|
|
||||||
Device device = devices.get(offer.id);
|
|
||||||
if (device == null) {
|
|
||||||
device = new Device(BackgroundService.this, offer, Device.PairStatus.NotPaired);
|
|
||||||
devices.put(offer.id, device);
|
|
||||||
Log.e("KDE/BackgroundService", "device stored: " + offer.id);
|
|
||||||
}
|
|
||||||
// TEST
|
|
||||||
|
|
||||||
offer.connect();
|
|
||||||
|
|
||||||
|
|
||||||
onDeviceListChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onOfferRemoved(String id) {
|
|
||||||
Log.e("KDE/BackgroundService", "offer removed: " + id);
|
|
||||||
deviceOffers.remove(id);
|
|
||||||
if (devices.get(id) != null && !devices.get(id).isReachable() && !devices.get(id).isPaired()) {
|
|
||||||
devices.remove(id);
|
|
||||||
}
|
|
||||||
onDeviceListChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLinkConnected(DeviceOffer offer, DeviceLink link) {
|
|
||||||
String deviceId = link.getDeviceId();
|
|
||||||
Log.e("KDE/BackgroundService", "device connected: " + deviceId);
|
|
||||||
Device device = devices.get(deviceId);
|
Device device = devices.get(deviceId);
|
||||||
if (device == null) {
|
|
||||||
device = new Device(BackgroundService.this, offer, Device.PairStatus.Paired);
|
if (device != null) {
|
||||||
devices.put(link.getDeviceId(), device);
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
device.addLink(link);
|
|
||||||
onDeviceListChanged();
|
onDeviceListChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLinkDisconnected(DeviceLink link) {
|
public void onConnectionLost(BaseLink link) {
|
||||||
Device d = devices.get(link);
|
Device d = devices.get(link.getDeviceId());
|
||||||
Log.i("KDE/onConnectionLost", "removeLink, deviceId: " + link.getDeviceId());
|
Log.i("KDE/onConnectionLost", "removeLink, deviceId: " + link.getDeviceId());
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
d.removeLink(link);
|
d.removeLink(link);
|
||||||
@@ -228,12 +230,6 @@ public class BackgroundService extends Service {
|
|||||||
}
|
}
|
||||||
onDeviceListChanged();
|
onDeviceListChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConnectionFailed(DeviceOffer offer, String reason) {
|
|
||||||
Log.e("KDE/BackgroundService", "device connect failed: " + reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public ConcurrentHashMap<String, Device> getDevices() {
|
public ConcurrentHashMap<String, Device> getDevices() {
|
||||||
@@ -241,15 +237,8 @@ public class BackgroundService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onNetworkChange() {
|
public void onNetworkChange() {
|
||||||
for (DeviceOffer d : deviceOffers.values()) {
|
|
||||||
Log.e("YESOFFER" , "OFFER " + d.name);
|
|
||||||
}
|
|
||||||
for (Device d : devices.values()) {
|
|
||||||
Log.e("NOTOFFER" , "DEVICE " + d.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (BaseLinkProvider a : linkProviders) {
|
for (BaseLinkProvider a : linkProviders) {
|
||||||
a.refresh();
|
a.onNetworkChange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,7 +290,7 @@ public class BackgroundService extends Service {
|
|||||||
addConnectionListener(deviceListener);
|
addConnectionListener(deviceListener);
|
||||||
|
|
||||||
for (BaseLinkProvider a : linkProviders) {
|
for (BaseLinkProvider a : linkProviders) {
|
||||||
a.refresh();
|
a.onStart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,10 +402,9 @@ public class BackgroundService extends Service {
|
|||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
stopForeground(true);
|
stopForeground(true);
|
||||||
/*
|
|
||||||
for (BaseLinkProvider a : linkProviders) {
|
for (BaseLinkProvider a : linkProviders) {
|
||||||
a.onStop();
|
a.onStop();
|
||||||
}*/
|
}
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -41,11 +41,11 @@ import androidx.core.content.ContextCompat;
|
|||||||
|
|
||||||
import org.apache.commons.collections4.MultiValuedMap;
|
import org.apache.commons.collections4.MultiValuedMap;
|
||||||
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
|
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
|
||||||
import org.kde.kdeconnect.Backends.DeviceLink;
|
import org.kde.kdeconnect.Backends.BaseLink;
|
||||||
import org.kde.kdeconnect.Backends.BasePairingHandler;
|
import org.kde.kdeconnect.Backends.BasePairingHandler;
|
||||||
import org.kde.kdeconnect.Backends.DeviceOffer;
|
|
||||||
import org.kde.kdeconnect.Helpers.DeviceHelper;
|
import org.kde.kdeconnect.Helpers.DeviceHelper;
|
||||||
import org.kde.kdeconnect.Helpers.NotificationHelper;
|
import org.kde.kdeconnect.Helpers.NotificationHelper;
|
||||||
|
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
|
||||||
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.UserInterface.MainActivity;
|
import org.kde.kdeconnect.UserInterface.MainActivity;
|
||||||
@@ -66,7 +66,7 @@ import java.util.Vector;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
public class Device implements DeviceLink.PacketReceiver {
|
public class Device implements BaseLink.PacketReceiver {
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ public class Device implements DeviceLink.PacketReceiver {
|
|||||||
private final CopyOnWriteArrayList<PairingCallback> pairingCallback = new CopyOnWriteArrayList<>();
|
private final CopyOnWriteArrayList<PairingCallback> pairingCallback = new CopyOnWriteArrayList<>();
|
||||||
private final Map<String, BasePairingHandler> pairingHandlers = new HashMap<>();
|
private final Map<String, BasePairingHandler> pairingHandlers = new HashMap<>();
|
||||||
|
|
||||||
private final CopyOnWriteArrayList<DeviceLink> links = new CopyOnWriteArrayList<>();
|
private final CopyOnWriteArrayList<BaseLink> links = new CopyOnWriteArrayList<>();
|
||||||
private DevicePacketQueue packetQueue;
|
private DevicePacketQueue packetQueue;
|
||||||
|
|
||||||
private List<String> supportedPlugins = new ArrayList<>();
|
private List<String> supportedPlugins = new ArrayList<>();
|
||||||
@@ -170,28 +170,21 @@ public class Device implements DeviceLink.PacketReceiver {
|
|||||||
//reloadPluginsFromSettings();
|
//reloadPluginsFromSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Remembered trusted device, we need to wait for a incoming devicelink to communicate
|
//Device known via an incoming connection sent to us via a devicelink, we know everything but we don't trust it yet
|
||||||
Device(Context context, DeviceOffer deviceOffer, PairStatus paired) {
|
Device(Context context, NetworkPacket np, BaseLink dl) {
|
||||||
settings = context.getSharedPreferences(deviceOffer.id, Context.MODE_PRIVATE);
|
|
||||||
|
//Log.e("Device","Constructor B");
|
||||||
|
|
||||||
Log.e("AAAAA", "Adding device "+deviceOffer.name);
|
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.deviceId = deviceOffer.id;
|
this.deviceId = np.getString("deviceId");
|
||||||
this.name = deviceOffer.name;
|
this.name = context.getString(R.string.unknown_device); //We read it in addLink
|
||||||
this.pairStatus = paired;
|
this.pairStatus = PairStatus.NotPaired;
|
||||||
this.protocolVersion = deviceOffer.protocolVersion;
|
this.protocolVersion = 0;
|
||||||
this.deviceType = deviceOffer.type;
|
this.deviceType = DeviceType.Computer;
|
||||||
|
|
||||||
SharedPreferences.Editor editor = settings.edit();
|
settings = context.getSharedPreferences(deviceId, Context.MODE_PRIVATE);
|
||||||
editor.putString("deviceName", this.name);
|
|
||||||
editor.putString("deviceType", this.deviceType.toString());
|
|
||||||
editor.apply();
|
|
||||||
|
|
||||||
//Assume every plugin is supported until addLink is called and we can get the actual list
|
addLink(np, dl);
|
||||||
supportedPlugins = new Vector<>(PluginFactory.getAvailablePlugins());
|
|
||||||
|
|
||||||
//Do not load plugins yet, the device is not present
|
|
||||||
//reloadPluginsFromSettings();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@@ -441,7 +434,7 @@ public class Device implements DeviceLink.PacketReceiver {
|
|||||||
return !links.isEmpty();
|
return !links.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addLink(DeviceLink link) {
|
public void addLink(NetworkPacket identityPacket, BaseLink link) {
|
||||||
if (links.isEmpty()) {
|
if (links.isEmpty()) {
|
||||||
packetQueue = new DevicePacketQueue(this);
|
packetQueue = new DevicePacketQueue(this);
|
||||||
}
|
}
|
||||||
@@ -449,6 +442,31 @@ public class Device implements DeviceLink.PacketReceiver {
|
|||||||
links.add(link);
|
links.add(link);
|
||||||
link.addPacketReceiver(this);
|
link.addPacketReceiver(this);
|
||||||
|
|
||||||
|
this.protocolVersion = identityPacket.getInt("protocolVersion");
|
||||||
|
|
||||||
|
if (identityPacket.has("deviceName")) {
|
||||||
|
this.name = identityPacket.getString("deviceName", this.name);
|
||||||
|
SharedPreferences.Editor editor = settings.edit();
|
||||||
|
editor.putString("deviceName", this.name);
|
||||||
|
editor.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (identityPacket.has("deviceType")) {
|
||||||
|
this.deviceType = DeviceType.FromString(identityPacket.getString("deviceType", "desktop"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (identityPacket.has("certificate")) {
|
||||||
|
String certificateString = identityPacket.getString("certificate");
|
||||||
|
|
||||||
|
try {
|
||||||
|
byte[] certificateBytes = Base64.decode(certificateString, 0);
|
||||||
|
certificate = SslHelper.parseCertificate(certificateBytes);
|
||||||
|
Log.i("KDE/Device", "Got certificate ");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("KDE/Device", "Error getting certificate", e);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SharedPreferences globalSettings = PreferenceManager.getDefaultSharedPreferences(context);
|
SharedPreferences globalSettings = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
@@ -459,7 +477,7 @@ public class Device implements DeviceLink.PacketReceiver {
|
|||||||
Log.e("KDE/Device", "Exception reading our own private key", e); //Should not happen
|
Log.e("KDE/Device", "Exception reading our own private key", e); //Should not happen
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i("KDE/Device", "addLink " + link + " -> " + getName() + " active links: " + links.size());
|
Log.i("KDE/Device", "addLink " + link.getLinkProvider().getName() + " -> " + getName() + " active links: " + links.size());
|
||||||
|
|
||||||
if (!pairingHandlers.containsKey(link.getName())) {
|
if (!pairingHandlers.containsKey(link.getName())) {
|
||||||
BasePairingHandler.PairingHandlerCallback callback = new BasePairingHandler.PairingHandlerCallback() {
|
BasePairingHandler.PairingHandlerCallback callback = new BasePairingHandler.PairingHandlerCallback() {
|
||||||
@@ -490,10 +508,11 @@ public class Device implements DeviceLink.PacketReceiver {
|
|||||||
pairingHandlers.put(link.getName(), link.getPairingHandler(this, callback));
|
pairingHandlers.put(link.getName(), link.getPairingHandler(this, callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<String> outgoingCapabilities = new HashSet<>();
|
Set<String> outgoingCapabilities = identityPacket.getStringSet("outgoingCapabilities", null);
|
||||||
Set<String> incomingCapabilities = new HashSet<>();
|
Set<String> incomingCapabilities = identityPacket.getStringSet("incomingCapabilities", null);
|
||||||
|
|
||||||
if (!incomingCapabilities.isEmpty() && !outgoingCapabilities.isEmpty()) {
|
|
||||||
|
if (incomingCapabilities != null && outgoingCapabilities != null) {
|
||||||
supportedPlugins = new Vector<>(PluginFactory.pluginsForCapabilities(incomingCapabilities, outgoingCapabilities));
|
supportedPlugins = new Vector<>(PluginFactory.pluginsForCapabilities(incomingCapabilities, outgoingCapabilities));
|
||||||
} else {
|
} else {
|
||||||
supportedPlugins = new Vector<>(PluginFactory.getAvailablePlugins());
|
supportedPlugins = new Vector<>(PluginFactory.getAvailablePlugins());
|
||||||
@@ -504,12 +523,12 @@ public class Device implements DeviceLink.PacketReceiver {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeLink(DeviceLink link) {
|
public void removeLink(BaseLink link) {
|
||||||
//FilesHelper.LogOpenFileCount();
|
//FilesHelper.LogOpenFileCount();
|
||||||
|
|
||||||
/* Remove pairing handler corresponding to that link too if it was the only link*/
|
/* Remove pairing handler corresponding to that link too if it was the only link*/
|
||||||
boolean linkPresent = false;
|
boolean linkPresent = false;
|
||||||
for (DeviceLink bl : links) {
|
for (BaseLink bl : links) {
|
||||||
if (bl.getName().equals(link.getName())) {
|
if (bl.getName().equals(link.getName())) {
|
||||||
linkPresent = true;
|
linkPresent = true;
|
||||||
break;
|
break;
|
||||||
@@ -521,7 +540,7 @@ public class Device implements DeviceLink.PacketReceiver {
|
|||||||
|
|
||||||
link.removePacketReceiver(this);
|
link.removePacketReceiver(this);
|
||||||
links.remove(link);
|
links.remove(link);
|
||||||
Log.i("KDE/Device", "removeLink: " + link + " -> " + getName() + " active links: " + links.size());
|
Log.i("KDE/Device", "removeLink: " + link.getLinkProvider().getName() + " -> " + getName() + " active links: " + links.size());
|
||||||
if (links.isEmpty()) {
|
if (links.isEmpty()) {
|
||||||
reloadPluginsFromSettings();
|
reloadPluginsFromSettings();
|
||||||
if (packetQueue != null) {
|
if (packetQueue != null) {
|
||||||
@@ -670,7 +689,7 @@ public class Device implements DeviceLink.PacketReceiver {
|
|||||||
* @param np the packet to send
|
* @param np the packet to send
|
||||||
* @param callback a callback that can receive realtime updates
|
* @param callback a callback that can receive realtime updates
|
||||||
* @return true if the packet was sent ok, false otherwise
|
* @return true if the packet was sent ok, false otherwise
|
||||||
* @see DeviceLink#sendPacket(NetworkPacket, SendPacketStatusCallback)
|
* @see BaseLink#sendPacket(NetworkPacket, SendPacketStatusCallback)
|
||||||
*/
|
*/
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
public boolean sendPacketBlocking(final NetworkPacket np, final SendPacketStatusCallback callback) {
|
public boolean sendPacketBlocking(final NetworkPacket np, final SendPacketStatusCallback callback) {
|
||||||
@@ -684,7 +703,7 @@ public class Device implements DeviceLink.PacketReceiver {
|
|||||||
|
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
//Make a copy to avoid concurrent modification exception if the original list changes
|
//Make a copy to avoid concurrent modification exception if the original list changes
|
||||||
for (final DeviceLink link : links) {
|
for (final BaseLink link : links) {
|
||||||
if (link == null)
|
if (link == null)
|
||||||
continue; //Since we made a copy, maybe somebody destroyed the link in the meanwhile
|
continue; //Since we made a copy, maybe somebody destroyed the link in the meanwhile
|
||||||
success = link.sendPacket(np, callback);
|
success = link.sendPacket(np, callback);
|
||||||
@@ -861,10 +880,27 @@ public class Device implements DeviceLink.PacketReceiver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void disconnect() {
|
public void disconnect() {
|
||||||
for (DeviceLink link : links) {
|
for (BaseLink link : links) {
|
||||||
link.disconnect();
|
link.disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
@@ -51,11 +51,11 @@ import androidx.core.content.ContextCompat;
|
|||||||
import androidx.core.graphics.drawable.DrawableCompat;
|
import androidx.core.graphics.drawable.DrawableCompat;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
import org.kde.kdeconnect.Backends.DeviceLink;
|
import org.kde.kdeconnect.Backends.BaseLink;
|
||||||
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
||||||
import org.kde.kdeconnect.Backends.DeviceOffer;
|
|
||||||
import org.kde.kdeconnect.BackgroundService;
|
import org.kde.kdeconnect.BackgroundService;
|
||||||
import org.kde.kdeconnect.Helpers.VideoUrlsHelper;
|
import org.kde.kdeconnect.Helpers.VideoUrlsHelper;
|
||||||
|
import org.kde.kdeconnect.NetworkPacket;
|
||||||
import org.kde.kdeconnect.Plugins.SystemvolumePlugin.SystemvolumeFragment;
|
import org.kde.kdeconnect.Plugins.SystemvolumePlugin.SystemvolumeFragment;
|
||||||
import org.kde.kdeconnect.UserInterface.ThemeUtil;
|
import org.kde.kdeconnect.UserInterface.ThemeUtil;
|
||||||
import org.kde.kdeconnect_tp.R;
|
import org.kde.kdeconnect_tp.R;
|
||||||
@@ -237,32 +237,15 @@ public class MprisActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final BaseLinkProvider.ConnectionReceiver connectionReceiver = new BaseLinkProvider.ConnectionReceiver() {
|
private final BaseLinkProvider.ConnectionReceiver connectionReceiver = new BaseLinkProvider.ConnectionReceiver() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOfferAdded(DeviceOffer offer) {
|
public void onConnectionReceived(NetworkPacket identityPacket, BaseLink link) {
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onOfferRemoved(String id) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLinkConnected(DeviceOffer offer, DeviceLink link) {
|
|
||||||
connectToPlugin(null);
|
connectToPlugin(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConnectionFailed(DeviceOffer offer, String reason) {
|
public void onConnectionLost(BaseLink link) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLinkDisconnected(DeviceLink link) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Reference in New Issue
Block a user