mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-08-29 21:27:40 +00:00
Failed mega refactor
This commit is contained in:
parent
d8749d8f85
commit
cf32416243
@ -20,8 +20,6 @@
|
|||||||
|
|
||||||
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 {
|
||||||
@ -29,38 +27,47 @@ 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 onConnectionReceived(NetworkPacket identityPacket, BaseLink link);
|
void onOfferAdded(DeviceOffer offer);
|
||||||
void onConnectionLost(BaseLink link);
|
void onOfferRemoved(String id);
|
||||||
|
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); }
|
||||||
|
|
||||||
public boolean removeConnectionReceiver(ConnectionReceiver cr) {
|
protected void onOfferAdded(DeviceOffer offer) {
|
||||||
return connectionReceivers.remove(cr);
|
|
||||||
}
|
|
||||||
|
|
||||||
//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.onConnectionReceived(identityPacket, link);
|
cr.onOfferAdded(offer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
protected void connectionLost(BaseLink link) {
|
protected void onOfferRemoved(String id) {
|
||||||
//Log.i("KDE/LinkProvider", "connectionLost");
|
|
||||||
for(ConnectionReceiver cr : connectionReceivers) {
|
for(ConnectionReceiver cr : connectionReceivers) {
|
||||||
cr.onConnectionLost(link);
|
cr.onOfferRemoved(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onLinkConnected(DeviceOffer offer, DeviceLink link) {
|
||||||
|
for(ConnectionReceiver cr : connectionReceivers) {
|
||||||
|
cr.onLinkConnected(offer, link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected void onConnectionFailed(DeviceOffer offer, String reason) {
|
||||||
|
for(ConnectionReceiver cr : connectionReceivers) {
|
||||||
|
cr.onConnectionFailed(offer, reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected void onLinkDisconnected(DeviceLink link) {
|
||||||
|
for(ConnectionReceiver cr : connectionReceivers) {
|
||||||
|
cr.onLinkDisconnected(link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//To override
|
//To override
|
||||||
public abstract void onStart();
|
public abstract void refresh();
|
||||||
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,17 +20,13 @@
|
|||||||
|
|
||||||
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.BaseLink;
|
import org.kde.kdeconnect.Backends.DeviceLink;
|
||||||
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;
|
||||||
@ -45,7 +41,7 @@ import java.util.UUID;
|
|||||||
|
|
||||||
import androidx.annotation.WorkerThread;
|
import androidx.annotation.WorkerThread;
|
||||||
|
|
||||||
public class BluetoothLink extends BaseLink {
|
public class BluetoothLink extends DeviceLink {
|
||||||
private final ConnectionMultiplexer connection;
|
private final ConnectionMultiplexer connection;
|
||||||
private final InputStream input;
|
private final InputStream input;
|
||||||
private final OutputStream output;
|
private final OutputStream output;
|
||||||
@ -203,10 +199,6 @@ public class BluetoothLink extends BaseLink {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean linkShouldBeKeptAlive() {
|
|
||||||
return receivingThread.isAlive();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
public boolean isConnected() {
|
public boolean isConnected() {
|
||||||
|
@ -35,6 +35,7 @@ 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;
|
||||||
|
|
||||||
@ -72,7 +73,9 @@ 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");
|
||||||
@ -89,7 +92,6 @@ public class BluetoothLinkProvider extends BaseLinkProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
if (bluetoothAdapter == null) {
|
if (bluetoothAdapter == null) {
|
||||||
return;
|
return;
|
||||||
@ -113,13 +115,11 @@ public class BluetoothLinkProvider extends BaseLinkProvider {
|
|||||||
new Thread(serverRunnable).start();
|
new Thread(serverRunnable).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void refresh() {
|
||||||
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,15 +129,19 @@ 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);
|
||||||
connectionLost(link);
|
onLinkDisconnected(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ServerRunnable implements Runnable {
|
private class ServerRunnable implements Runnable {
|
||||||
|
@ -31,7 +31,7 @@ import java.util.ArrayList;
|
|||||||
import androidx.annotation.WorkerThread;
|
import androidx.annotation.WorkerThread;
|
||||||
|
|
||||||
|
|
||||||
public abstract class BaseLink {
|
public abstract class DeviceLink {
|
||||||
|
|
||||||
protected final Context context;
|
protected final Context context;
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ public abstract class BaseLink {
|
|||||||
private final ArrayList<PacketReceiver> receivers = new ArrayList<>();
|
private final ArrayList<PacketReceiver> receivers = new ArrayList<>();
|
||||||
protected PrivateKey privateKey;
|
protected PrivateKey privateKey;
|
||||||
|
|
||||||
protected BaseLink(Context context, String deviceId, BaseLinkProvider linkProvider) {
|
protected DeviceLink(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,15 +62,6 @@ public abstract class BaseLink {
|
|||||||
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);
|
||||||
}
|
}
|
||||||
@ -86,7 +77,7 @@ public abstract class BaseLink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void disconnect() {
|
public void disconnect() {
|
||||||
linkProvider.connectionLost(this);
|
linkProvider.onLinkDisconnected(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TO OVERRIDE, should be sync
|
//TO OVERRIDE, should be sync
|
59
src/org/kde/kdeconnect/Backends/DeviceOffer.java
Normal file
59
src/org/kde/kdeconnect/Backends/DeviceOffer.java
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* 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.BaseLink;
|
import org.kde.kdeconnect.Backends.DeviceLink;
|
||||||
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 BaseLink {
|
public class LanLink extends DeviceLink {
|
||||||
|
|
||||||
public interface LinkDisconnectedCallback {
|
public interface LinkDisconnectedCallback {
|
||||||
void linkDisconnected(LanLink brokenLink);
|
void linkDisconnected(LanLink brokenLink);
|
||||||
@ -260,15 +260,4 @@ public class LanLink extends BaseLink {
|
|||||||
|
|
||||||
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,8 +26,9 @@ 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.BaseLink;
|
import org.kde.kdeconnect.Backends.DeviceLink;
|
||||||
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;
|
||||||
@ -89,7 +90,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);
|
||||||
connectionLost(brokenLink);
|
onLinkDisconnected(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.
|
||||||
@ -164,7 +165,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
|
||||||
onNetworkChange();
|
refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -262,7 +263,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, BaseLink)} crashes on some devices running Oreo 8.1 (SDK level 27).
|
* {@link Device#addLink(NetworkPacket, DeviceLink)} 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
|
||||||
@ -284,12 +285,14 @@ 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);
|
||||||
connectionAccepted(identityPacket, link);
|
onLinkConnected(DeviceOffer.FromLegacyIdentityPacket(identityPacket), link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public LanLinkProvider(Context context) {
|
public LanLinkProvider(Context context)
|
||||||
|
{
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
onStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupUdpListener() {
|
private void setupUdpListener() {
|
||||||
@ -413,7 +416,6 @@ 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) {
|
||||||
@ -428,11 +430,10 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNetworkChange() {
|
public void refresh() {
|
||||||
broadcastUdpPacket();
|
broadcastUdpPacket();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
//Log.i("KDE/LanLinkProvider", "onStop");
|
//Log.i("KDE/LanLinkProvider", "onStop");
|
||||||
listening = false;
|
listening = false;
|
||||||
@ -453,4 +454,9 @@ 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.BaseLink;
|
import org.kde.kdeconnect.Backends.DeviceLink;
|
||||||
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 BaseLink {
|
public class LoopbackLink extends DeviceLink {
|
||||||
|
|
||||||
public LoopbackLink(Context context, BaseLinkProvider linkProvider) {
|
public LoopbackLink(Context context, BaseLinkProvider linkProvider) {
|
||||||
super(context, "loopback", linkProvider);
|
super(context, "loopback", linkProvider);
|
||||||
|
@ -23,6 +23,9 @@ 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 {
|
||||||
@ -34,25 +37,20 @@ public class LoopbackLinkProvider extends BaseLinkProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void connect(DeviceOffer offer) {
|
||||||
onNetworkChange();
|
onLinkConnected(offer, new LoopbackLink(context, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop() {
|
public void refresh() {
|
||||||
|
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.BaseLink;
|
import org.kde.kdeconnect.Backends.DeviceLink;
|
||||||
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 BaseLink {
|
public class MulticastLink extends DeviceLink {
|
||||||
|
|
||||||
static final String LOG_TAG = "MulticastLink";
|
static final String LOG_TAG = "MulticastLink";
|
||||||
|
|
||||||
@ -57,11 +57,6 @@ public class MulticastLink extends BaseLink {
|
|||||||
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;
|
||||||
@ -77,13 +72,11 @@ public class MulticastLink extends BaseLink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Returns the old socket
|
//Returns the old socket
|
||||||
public SSLSocket reset(final SSLSocket newSocket, ConnectionStarted connectionSource) throws IOException {
|
public SSLSocket reset(final SSLSocket newSocket) 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
|
||||||
}
|
}
|
||||||
@ -122,10 +115,10 @@ public class MulticastLink extends BaseLink {
|
|||||||
return oldSocket;
|
return oldSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MulticastLink(Context context, String deviceId, MulticastLinkProvider linkProvider, SSLSocket socket, ConnectionStarted connectionSource) throws IOException {
|
public MulticastLink(Context context, String deviceId, MulticastLinkProvider linkProvider, SSLSocket socket) throws IOException {
|
||||||
super(context, deviceId, linkProvider);
|
super(context, deviceId, linkProvider);
|
||||||
callback = linkProvider;
|
callback = linkProvider;
|
||||||
reset(socket, connectionSource);
|
reset(socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -255,14 +248,4 @@ public class MulticastLink extends BaseLink {
|
|||||||
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,40 +24,36 @@ 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.json.JSONException;
|
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;
|
||||||
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,13 +65,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;
|
||||||
@ -89,31 +85,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);
|
||||||
connectionLost(brokenLink);
|
onLinkDisconnected(brokenLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
// They received my mDNS broadcast and are connecting to me. The first thing they send should be their identity.
|
private InetAddress getDeviceIpAddress() {
|
||||||
private void tcpPacketReceived(Socket socket) {
|
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
|
||||||
|
WifiManager.MulticastLock lock = wifi.createMulticastLock("jmdns-multicast-lock");
|
||||||
writeIdentity(socket);
|
lock.setReferenceCounted(true);
|
||||||
NetworkPacket otherIdentity = readIdentity(socket);
|
lock.acquire();
|
||||||
|
InetAddress result = null;
|
||||||
if (!otherIdentity.getType().equals(NetworkPacket.PACKET_TYPE_IDENTITY)) {
|
try {
|
||||||
Log.e(LOG_TAG, "Expecting an identity package instead of " + otherIdentity.getType());
|
// figure out our wifi address, otherwise bail
|
||||||
return;
|
WifiInfo wifiinfo = wifi.getConnectionInfo();
|
||||||
|
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);
|
||||||
@ -122,58 +118,34 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a new 'identity' packet is received. Those are passed here by
|
* Called when a socket is connected.
|
||||||
* {@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 identityPacketReceived(final NetworkPacket identityPacket, final Socket socket, final MulticastLink.ConnectionStarted connectionStarted) {
|
private void doTheSslDance(DeviceOffer deviceOffer, final Socket socket, final MulticastLink.ConnectionStarted connectionStarted) {
|
||||||
|
|
||||||
String myId = DeviceHelper.getDeviceId(context);
|
String deviceId = deviceOffer.id;
|
||||||
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);
|
||||||
|
|
||||||
if (isDeviceTrusted && !SslHelper.isCertificateStored(context, deviceId)) {
|
Log.i(LOG_TAG, "Starting SSL handshake with " + deviceOffer.name + " trusted:" + isDeviceTrusted);
|
||||||
//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];
|
||||||
identityPacket.set("certificate", Base64.encodeToString(certificate.getEncoded(), 0));
|
createLink(deviceOffer, sslsocket);
|
||||||
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) {
|
||||||
Log.e(LOG_TAG, "Handshake as " + mode + " failed with " + identityPacket.getString("deviceName"), e);
|
String mode = clientMode ? "client" : "server";
|
||||||
|
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;
|
||||||
@ -188,7 +160,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 " + identityPacket.getString("deviceName"), e);
|
Log.e(LOG_TAG, "Handshake failed with " + deviceOffer.name, e);
|
||||||
|
|
||||||
//String[] ciphers = sslsocket.getSupportedCipherSuites();
|
//String[] ciphers = sslsocket.getSupportedCipherSuites();
|
||||||
//for (String cipher : ciphers) {
|
//for (String cipher : ciphers) {
|
||||||
@ -207,7 +179,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, BaseLink)} crashes on some devices running Oreo 8.1 (SDK level 27).
|
* {@link Device#addLink(NetworkPacket, DeviceLink)} 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
|
||||||
@ -215,53 +187,50 @@ 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 addLink(final NetworkPacket identityPacket, SSLSocket socket, MulticastLink.ConnectionStarted connectionOrigin) throws IOException {
|
private void createLink(DeviceOffer offer, SSLSocket socket) 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, connectionOrigin);
|
final Socket oldSocket = currentLink.reset(socket);
|
||||||
//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, connectionOrigin);
|
MulticastLink link = new MulticastLink(context, deviceId, this, socket);
|
||||||
visibleComputers.put(deviceId, link);
|
visibleComputers.put(deviceId, link);
|
||||||
connectionAccepted(identityPacket, link);
|
onLinkConnected(offer, 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() {
|
||||||
@ -276,14 +245,21 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
|
|||||||
try {
|
try {
|
||||||
Socket socket = tcpServer.accept();
|
Socket socket = tcpServer.accept();
|
||||||
configureSocket(socket);
|
configureSocket(socket);
|
||||||
tcpPacketReceived(socket);
|
InetAddress remoteAddress = socket.getInetAddress();
|
||||||
|
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 {
|
||||||
@ -305,78 +281,37 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
|
|||||||
throw new RuntimeException("This should not be reachable");
|
throw new RuntimeException("This should not be reachable");
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
NsdManager.RegistrationListener mRegistrationListener = new NsdManager.RegistrationListener() {
|
||||||
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);
|
|
||||||
try {
|
@Override
|
||||||
mNsdManager.unregisterService(registrationListener);
|
public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
|
||||||
} catch (java.lang.IllegalArgumentException e) {
|
// Registration failed! Put debugging code here to determine why.
|
||||||
// not yet registered, but it's fine.
|
Log.e(LOG_TAG, "Registration failed");
|
||||||
}
|
}
|
||||||
NsdServiceInfo serviceInfo = new NsdServiceInfo();
|
|
||||||
|
|
||||||
// The name is subject to change based on conflicts
|
@Override
|
||||||
// with other services advertised on the same network.
|
public void onServiceUnregistered(NsdServiceInfo serviceInfo) {
|
||||||
NetworkPacket myIdentity = NetworkPacket.createIdentityPacket(context);
|
// Service has been unregistered. This only happens when you call
|
||||||
String did = myIdentity.getString("deviceID");
|
// NsdManager.unregisterService() and pass in this listener.
|
||||||
String name = myIdentity.getString("deviceName");
|
|
||||||
InetAddress addr = this.tcpServer.getInetAddress();
|
|
||||||
int port = this.tcpServer.getLocalPort();
|
|
||||||
|
|
||||||
// These cause the requirement for api level 21.
|
Log.e(LOG_TAG, "Service unregistered: " + serviceInfo);
|
||||||
serviceInfo.setAttribute("name", myIdentity.getString("deviceName"));
|
offers.remove(serviceInfo.getHost());
|
||||||
serviceInfo.setAttribute("id", myIdentity.getString("deviceId"));
|
}
|
||||||
serviceInfo.setAttribute("type", myIdentity.getString("deviceType"));
|
|
||||||
serviceInfo.setAttribute("version", myIdentity.getString("protocolVersion"));
|
|
||||||
|
|
||||||
// It might be nice to add the capabilities in the mDNS advertisement too, but without
|
@Override
|
||||||
// some kind of encoding that is too large for the TXT record
|
public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
|
||||||
|
// Unregistration failed. Put debugging code here to determine why.
|
||||||
serviceInfo.setServiceName("KDE Connect on " + myIdentity.getString("deviceName"));
|
Log.e(LOG_TAG, "Unregister of " + serviceInfo + " failed with: " + errorCode);
|
||||||
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() {
|
||||||
@ -387,120 +322,134 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
String getString(NsdServiceInfo serviceInfo, String key) {
|
||||||
|
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.i(LOG_TAG, "Successfully resolved " + serviceInfo);
|
Log.e(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();
|
||||||
|
|
||||||
SocketFactory socketFactory = SocketFactory.getDefault();
|
DeviceOffer offer = new DeviceOffer();
|
||||||
Socket socket;
|
offer.id = id;
|
||||||
try {
|
offer.name = name;
|
||||||
socket = socketFactory.createSocket(hostname, remotePort);
|
offer.type = type;
|
||||||
} catch (IOException e) {
|
offer.protocolVersion = protocolVersion;
|
||||||
Log.e(LOG_TAG, "Unable to open socket to mDNS remote: " + serviceInfo, e);
|
offer.host = hostname;
|
||||||
return;
|
offer.port = remotePort;
|
||||||
}
|
offer.provider = MulticastLinkProvider.this;
|
||||||
|
|
||||||
writeIdentity(socket);
|
offers.put(hostname, offer);
|
||||||
NetworkPacket otherIdentity = readIdentity(socket);
|
onOfferAdded(offer);
|
||||||
|
|
||||||
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() {
|
|
||||||
|
|
||||||
// Called as soon as service discovery begins.
|
NsdManager.DiscoveryListener discoveryListener = new NsdManager.DiscoveryListener() {
|
||||||
@Override
|
|
||||||
public void onDiscoveryStarted(String regType) {
|
|
||||||
Log.d(LOG_TAG, "Service discovery started");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
// Called as soon as service discovery begins.
|
||||||
public void onServiceFound(NsdServiceInfo service) {
|
@Override
|
||||||
// A service was found! Do something with it.
|
public void onDiscoveryStarted(String regType) {
|
||||||
Log.d(LOG_TAG, "Service discovery success" + service);
|
Log.e(LOG_TAG, "Service discovery started");
|
||||||
mNsdManager.resolveService(service, createResolveListener());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onServiceLost(NsdServiceInfo service) {
|
|
||||||
// When the network service is no longer available.
|
|
||||||
// Internal bookkeeping code goes here.
|
|
||||||
Log.e(LOG_TAG, "service lost: " + service);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDiscoveryStopped(String serviceType) {
|
|
||||||
Log.i(LOG_TAG, "Discovery stopped: " + serviceType);
|
|
||||||
listening = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
|
|
||||||
Log.e(LOG_TAG, "Discovery failed: Error code:" + errorCode);
|
|
||||||
mNsdManager.stopServiceDiscovery(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
|
|
||||||
Log.e(LOG_TAG, "Discovery failed: Error code:" + errorCode);
|
|
||||||
mNsdManager.stopServiceDiscovery(this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
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) {
|
@Override
|
||||||
listening = true;
|
public void onServiceFound(NsdServiceInfo service) {
|
||||||
|
// A service was found! Do something with it.
|
||||||
// Need to set up TCP before setting up mDNS because we need to know the TCP listening
|
Log.e(LOG_TAG, "Service discovery success " + service);
|
||||||
// address and port
|
mNsdManager.resolveService(service, createResolveListener());
|
||||||
setupTcpListener();
|
|
||||||
|
|
||||||
initializeRegistrationListener();
|
|
||||||
|
|
||||||
initializeNsdManager(mRegistrationListener);
|
|
||||||
|
|
||||||
initializeDiscoveryListener();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public void onServiceLost(NsdServiceInfo service) {
|
||||||
|
// When the network service is no longer available.
|
||||||
|
// Internal bookkeeping code goes here.
|
||||||
|
Log.e(LOG_TAG, "service lost: " + service);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDiscoveryStopped(String serviceType) {
|
||||||
|
Log.e(LOG_TAG, "Discovery stopped: " + serviceType);
|
||||||
|
listening = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
|
||||||
|
Log.e(LOG_TAG, "Discovery failed: Error code:" + errorCode);
|
||||||
|
mNsdManager.stopServiceDiscovery(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
|
||||||
|
Log.e(LOG_TAG, "Discovery failed: Error code:" + errorCode);
|
||||||
|
mNsdManager.stopServiceDiscovery(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNetworkChange() {
|
public void refresh() {
|
||||||
onStop();
|
onStop();
|
||||||
onStart();
|
onStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public synchronized void onStart() {
|
||||||
public void onStop() {
|
Log.e(LOG_TAG,"ON_START");
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
if (!listening) {
|
||||||
// This backend does not work on older Android versions
|
Log.e(LOG_TAG,"ON_START doing things");
|
||||||
return;
|
listening = true;
|
||||||
|
// 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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mNsdManager.unregisterService(mRegistrationListener);
|
public synchronized void onStop() {
|
||||||
tcpServer.close();
|
/*Log.e(LOG_TAG,"ON_STOP");
|
||||||
listening = false;
|
if (listening) {
|
||||||
|
Log.e(LOG_TAG,"ON_STOP doing things");
|
||||||
|
mNsdManager.stopServiceDiscovery(discoveryListener);
|
||||||
|
mNsdManager.unregisterService(mRegistrationListener);
|
||||||
|
try { tcpServer.close(); } catch (IOException ignore) { }
|
||||||
|
listening = false;
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -508,4 +457,29 @@ 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,8 +39,9 @@ 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.BaseLink;
|
import org.kde.kdeconnect.Backends.DeviceLink;
|
||||||
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;
|
||||||
@ -83,6 +84,7 @@ 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<>();
|
||||||
|
|
||||||
@ -100,19 +102,6 @@ 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() {
|
||||||
@ -163,7 +152,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));
|
||||||
@ -177,46 +166,55 @@ 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 onConnectionReceived(final NetworkPacket identityPacket, final BaseLink link) {
|
public void onOfferAdded(DeviceOffer offer) {
|
||||||
|
deviceOffers.put(offer.id, offer);
|
||||||
|
|
||||||
String deviceId = identityPacket.getString("deviceId");
|
|
||||||
|
|
||||||
Device device = devices.get(deviceId);
|
// TEST
|
||||||
|
Log.e("KDE/BackgroundService", "offer added: " + offer.id);
|
||||||
if (device != null) {
|
Device device = devices.get(offer.id);
|
||||||
Log.i("KDE/BackgroundService", "addLink, known device: " + deviceId);
|
if (device == null) {
|
||||||
device.addLink(identityPacket, link);
|
device = new Device(BackgroundService.this, offer, Device.PairStatus.NotPaired);
|
||||||
} else {
|
devices.put(offer.id, device);
|
||||||
Log.i("KDE/BackgroundService", "addLink,unknown device: " + deviceId);
|
Log.e("KDE/BackgroundService", "device stored: " + offer.id);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// TEST
|
||||||
|
|
||||||
|
offer.connect();
|
||||||
|
|
||||||
|
|
||||||
onDeviceListChanged();
|
onDeviceListChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConnectionLost(BaseLink link) {
|
public void onOfferRemoved(String id) {
|
||||||
Device d = devices.get(link.getDeviceId());
|
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);
|
||||||
|
if (device == null) {
|
||||||
|
device = new Device(BackgroundService.this, offer, Device.PairStatus.Paired);
|
||||||
|
devices.put(link.getDeviceId(), device);
|
||||||
|
}
|
||||||
|
device.addLink(link);
|
||||||
|
onDeviceListChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLinkDisconnected(DeviceLink link) {
|
||||||
|
Device d = devices.get(link);
|
||||||
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);
|
||||||
@ -230,6 +228,12 @@ 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() {
|
||||||
@ -237,8 +241,15 @@ 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.onNetworkChange();
|
a.refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,7 +301,7 @@ public class BackgroundService extends Service {
|
|||||||
addConnectionListener(deviceListener);
|
addConnectionListener(deviceListener);
|
||||||
|
|
||||||
for (BaseLinkProvider a : linkProviders) {
|
for (BaseLinkProvider a : linkProviders) {
|
||||||
a.onStart();
|
a.refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,9 +413,10 @@ 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.BaseLink;
|
import org.kde.kdeconnect.Backends.DeviceLink;
|
||||||
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 BaseLink.PacketReceiver {
|
public class Device implements DeviceLink.PacketReceiver {
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ public class Device implements BaseLink.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<BaseLink> links = new CopyOnWriteArrayList<>();
|
private final CopyOnWriteArrayList<DeviceLink> links = new CopyOnWriteArrayList<>();
|
||||||
private DevicePacketQueue packetQueue;
|
private DevicePacketQueue packetQueue;
|
||||||
|
|
||||||
private List<String> supportedPlugins = new ArrayList<>();
|
private List<String> supportedPlugins = new ArrayList<>();
|
||||||
@ -170,21 +170,28 @@ public class Device implements BaseLink.PacketReceiver {
|
|||||||
//reloadPluginsFromSettings();
|
//reloadPluginsFromSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Device known via an incoming connection sent to us via a devicelink, we know everything but we don't trust it yet
|
//Remembered trusted device, we need to wait for a incoming devicelink to communicate
|
||||||
Device(Context context, NetworkPacket np, BaseLink dl) {
|
Device(Context context, DeviceOffer deviceOffer, PairStatus paired) {
|
||||||
|
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 = np.getString("deviceId");
|
this.deviceId = deviceOffer.id;
|
||||||
this.name = context.getString(R.string.unknown_device); //We read it in addLink
|
this.name = deviceOffer.name;
|
||||||
this.pairStatus = PairStatus.NotPaired;
|
this.pairStatus = paired;
|
||||||
this.protocolVersion = 0;
|
this.protocolVersion = deviceOffer.protocolVersion;
|
||||||
this.deviceType = DeviceType.Computer;
|
this.deviceType = deviceOffer.type;
|
||||||
|
|
||||||
settings = context.getSharedPreferences(deviceId, Context.MODE_PRIVATE);
|
SharedPreferences.Editor editor = settings.edit();
|
||||||
|
editor.putString("deviceName", this.name);
|
||||||
|
editor.putString("deviceType", this.deviceType.toString());
|
||||||
|
editor.apply();
|
||||||
|
|
||||||
addLink(np, dl);
|
//Assume every plugin is supported until addLink is called and we can get the actual list
|
||||||
|
supportedPlugins = new Vector<>(PluginFactory.getAvailablePlugins());
|
||||||
|
|
||||||
|
//Do not load plugins yet, the device is not present
|
||||||
|
//reloadPluginsFromSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@ -434,7 +441,7 @@ public class Device implements BaseLink.PacketReceiver {
|
|||||||
return !links.isEmpty();
|
return !links.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addLink(NetworkPacket identityPacket, BaseLink link) {
|
public void addLink(DeviceLink link) {
|
||||||
if (links.isEmpty()) {
|
if (links.isEmpty()) {
|
||||||
packetQueue = new DevicePacketQueue(this);
|
packetQueue = new DevicePacketQueue(this);
|
||||||
}
|
}
|
||||||
@ -442,31 +449,6 @@ public class Device implements BaseLink.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);
|
||||||
@ -477,7 +459,7 @@ public class Device implements BaseLink.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.getLinkProvider().getName() + " -> " + getName() + " active links: " + links.size());
|
Log.i("KDE/Device", "addLink " + link + " -> " + 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() {
|
||||||
@ -508,11 +490,10 @@ public class Device implements BaseLink.PacketReceiver {
|
|||||||
pairingHandlers.put(link.getName(), link.getPairingHandler(this, callback));
|
pairingHandlers.put(link.getName(), link.getPairingHandler(this, callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<String> outgoingCapabilities = identityPacket.getStringSet("outgoingCapabilities", null);
|
Set<String> outgoingCapabilities = new HashSet<>();
|
||||||
Set<String> incomingCapabilities = identityPacket.getStringSet("incomingCapabilities", null);
|
Set<String> incomingCapabilities = new HashSet<>();
|
||||||
|
|
||||||
|
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());
|
||||||
@ -523,12 +504,12 @@ public class Device implements BaseLink.PacketReceiver {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeLink(BaseLink link) {
|
public void removeLink(DeviceLink 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 (BaseLink bl : links) {
|
for (DeviceLink bl : links) {
|
||||||
if (bl.getName().equals(link.getName())) {
|
if (bl.getName().equals(link.getName())) {
|
||||||
linkPresent = true;
|
linkPresent = true;
|
||||||
break;
|
break;
|
||||||
@ -540,7 +521,7 @@ public class Device implements BaseLink.PacketReceiver {
|
|||||||
|
|
||||||
link.removePacketReceiver(this);
|
link.removePacketReceiver(this);
|
||||||
links.remove(link);
|
links.remove(link);
|
||||||
Log.i("KDE/Device", "removeLink: " + link.getLinkProvider().getName() + " -> " + getName() + " active links: " + links.size());
|
Log.i("KDE/Device", "removeLink: " + link + " -> " + getName() + " active links: " + links.size());
|
||||||
if (links.isEmpty()) {
|
if (links.isEmpty()) {
|
||||||
reloadPluginsFromSettings();
|
reloadPluginsFromSettings();
|
||||||
if (packetQueue != null) {
|
if (packetQueue != null) {
|
||||||
@ -689,7 +670,7 @@ public class Device implements BaseLink.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 BaseLink#sendPacket(NetworkPacket, SendPacketStatusCallback)
|
* @see DeviceLink#sendPacket(NetworkPacket, SendPacketStatusCallback)
|
||||||
*/
|
*/
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
public boolean sendPacketBlocking(final NetworkPacket np, final SendPacketStatusCallback callback) {
|
public boolean sendPacketBlocking(final NetworkPacket np, final SendPacketStatusCallback callback) {
|
||||||
@ -703,7 +684,7 @@ public class Device implements BaseLink.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 BaseLink link : links) {
|
for (final DeviceLink 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);
|
||||||
@ -880,27 +861,10 @@ public class Device implements BaseLink.PacketReceiver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void disconnect() {
|
public void disconnect() {
|
||||||
for (BaseLink link : links) {
|
for (DeviceLink 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.BaseLink;
|
import org.kde.kdeconnect.Backends.DeviceLink;
|
||||||
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,15 +237,32 @@ 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 onConnectionReceived(NetworkPacket identityPacket, BaseLink link) {
|
public void onOfferAdded(DeviceOffer offer) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onOfferRemoved(String id) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLinkConnected(DeviceOffer offer, DeviceLink link) {
|
||||||
connectToPlugin(null);
|
connectToPlugin(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConnectionLost(BaseLink link) {
|
public void onConnectionFailed(DeviceOffer offer, String reason) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLinkDisconnected(DeviceLink link) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
x
Reference in New Issue
Block a user