mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-08-29 13:17:43 +00:00
Failed mega refactor
This commit is contained in:
parent
d8749d8f85
commit
cf32416243
@ -20,8 +20,6 @@
|
||||
|
||||
package org.kde.kdeconnect.Backends;
|
||||
|
||||
import org.kde.kdeconnect.NetworkPacket;
|
||||
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
public abstract class BaseLinkProvider {
|
||||
@ -29,38 +27,47 @@ public abstract class BaseLinkProvider {
|
||||
private final CopyOnWriteArrayList<ConnectionReceiver> connectionReceivers = new CopyOnWriteArrayList<>();
|
||||
|
||||
public interface ConnectionReceiver {
|
||||
void onConnectionReceived(NetworkPacket identityPacket, BaseLink link);
|
||||
void onConnectionLost(BaseLink link);
|
||||
void onOfferAdded(DeviceOffer offer);
|
||||
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) {
|
||||
connectionReceivers.add(cr);
|
||||
}
|
||||
public boolean removeConnectionReceiver(ConnectionReceiver cr) { return connectionReceivers.remove(cr); }
|
||||
|
||||
public boolean removeConnectionReceiver(ConnectionReceiver cr) {
|
||||
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");
|
||||
protected void onOfferAdded(DeviceOffer offer) {
|
||||
for(ConnectionReceiver cr : connectionReceivers) {
|
||||
cr.onConnectionReceived(identityPacket, link);
|
||||
cr.onOfferAdded(offer);
|
||||
}
|
||||
}
|
||||
protected void connectionLost(BaseLink link) {
|
||||
//Log.i("KDE/LinkProvider", "connectionLost");
|
||||
protected void onOfferRemoved(String id) {
|
||||
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
|
||||
public abstract void onStart();
|
||||
public abstract void onStop();
|
||||
public abstract void onNetworkChange();
|
||||
|
||||
//public abstract int getPriority();
|
||||
public abstract void refresh();
|
||||
public abstract String getName();
|
||||
|
||||
public abstract void connect(DeviceOffer id);
|
||||
}
|
||||
|
@ -20,17 +20,13 @@
|
||||
|
||||
package org.kde.kdeconnect.Backends.BluetoothBackend;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothServerSocket;
|
||||
import android.bluetooth.BluetoothSocket;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONException;
|
||||
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.Device;
|
||||
import org.kde.kdeconnect.NetworkPacket;
|
||||
@ -45,7 +41,7 @@ import java.util.UUID;
|
||||
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
public class BluetoothLink extends BaseLink {
|
||||
public class BluetoothLink extends DeviceLink {
|
||||
private final ConnectionMultiplexer connection;
|
||||
private final InputStream input;
|
||||
private final OutputStream output;
|
||||
@ -203,10 +199,6 @@ public class BluetoothLink extends BaseLink {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean linkShouldBeKeptAlive() {
|
||||
return receivingThread.isAlive();
|
||||
}
|
||||
|
||||
/*
|
||||
public boolean isConnected() {
|
||||
|
@ -35,6 +35,7 @@ import android.util.Log;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
||||
import org.kde.kdeconnect.Backends.DeviceOffer;
|
||||
import org.kde.kdeconnect.Device;
|
||||
import org.kde.kdeconnect.NetworkPacket;
|
||||
|
||||
@ -72,7 +73,9 @@ public class BluetoothLinkProvider extends BaseLinkProvider {
|
||||
return;
|
||||
}
|
||||
visibleComputers.put(deviceId, link);
|
||||
connectionAccepted(identityPacket, link);
|
||||
|
||||
onLinkConnected(DeviceOffer.FromLegacyIdentityPacket(identityPacket), link);
|
||||
|
||||
link.startListening();
|
||||
if (oldLink != null) {
|
||||
Log.i("BluetoothLinkProvider", "Removing old connection to same device");
|
||||
@ -89,7 +92,6 @@ public class BluetoothLinkProvider extends BaseLinkProvider {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
if (bluetoothAdapter == null) {
|
||||
return;
|
||||
@ -113,13 +115,11 @@ public class BluetoothLinkProvider extends BaseLinkProvider {
|
||||
new Thread(serverRunnable).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNetworkChange() {
|
||||
public void refresh() {
|
||||
onStop();
|
||||
onStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
if (bluetoothAdapter == null || clientRunnable == null || serverRunnable == null) {
|
||||
return;
|
||||
@ -129,15 +129,19 @@ public class BluetoothLinkProvider extends BaseLinkProvider {
|
||||
serverRunnable.stopProcessing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "BluetoothLinkProvider";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(DeviceOffer id) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public void disconnectedLink(BluetoothLink link, String deviceId, BluetoothDevice remoteAddress) {
|
||||
sockets.remove(remoteAddress);
|
||||
visibleComputers.remove(deviceId);
|
||||
connectionLost(link);
|
||||
onLinkDisconnected(link);
|
||||
}
|
||||
|
||||
private class ServerRunnable implements Runnable {
|
||||
|
@ -31,7 +31,7 @@ import java.util.ArrayList;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
|
||||
public abstract class BaseLink {
|
||||
public abstract class DeviceLink {
|
||||
|
||||
protected final Context context;
|
||||
|
||||
@ -44,7 +44,7 @@ public abstract class BaseLink {
|
||||
private final ArrayList<PacketReceiver> receivers = new ArrayList<>();
|
||||
protected PrivateKey privateKey;
|
||||
|
||||
protected BaseLink(Context context, String deviceId, BaseLinkProvider linkProvider) {
|
||||
protected DeviceLink(Context context, String deviceId, BaseLinkProvider linkProvider) {
|
||||
this.context = context;
|
||||
this.linkProvider = linkProvider;
|
||||
this.deviceId = deviceId;
|
||||
@ -62,15 +62,6 @@ public abstract class BaseLink {
|
||||
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) {
|
||||
receivers.add(pr);
|
||||
}
|
||||
@ -86,7 +77,7 @@ public abstract class BaseLink {
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
linkProvider.connectionLost(this);
|
||||
linkProvider.onLinkDisconnected(this);
|
||||
}
|
||||
|
||||
//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 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.Device;
|
||||
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
|
||||
@ -47,7 +47,7 @@ import javax.net.ssl.SSLSocket;
|
||||
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
public class LanLink extends BaseLink {
|
||||
public class LanLink extends DeviceLink {
|
||||
|
||||
public interface LinkDisconnectedCallback {
|
||||
void linkDisconnected(LanLink brokenLink);
|
||||
@ -260,15 +260,4 @@ public class LanLink extends BaseLink {
|
||||
|
||||
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.Log;
|
||||
|
||||
import org.kde.kdeconnect.Backends.BaseLink;
|
||||
import org.kde.kdeconnect.Backends.DeviceLink;
|
||||
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
||||
import org.kde.kdeconnect.Backends.DeviceOffer;
|
||||
import org.kde.kdeconnect.BackgroundService;
|
||||
import org.kde.kdeconnect.Device;
|
||||
import org.kde.kdeconnect.Helpers.DeviceHelper;
|
||||
@ -89,7 +90,7 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
|
||||
public void linkDisconnected(LanLink brokenLink) {
|
||||
String deviceId = brokenLink.getDeviceId();
|
||||
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.
|
||||
@ -164,7 +165,7 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
|
||||
}, 5 * 1000);
|
||||
|
||||
// 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.
|
||||
* <p>
|
||||
* 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>
|
||||
*
|
||||
* @param identityPacket representation of remote device
|
||||
@ -284,12 +285,14 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
|
||||
//Let's create the link
|
||||
LanLink link = new LanLink(context, deviceId, this, socket, connectionOrigin);
|
||||
visibleComputers.put(deviceId, link);
|
||||
connectionAccepted(identityPacket, link);
|
||||
onLinkConnected(DeviceOffer.FromLegacyIdentityPacket(identityPacket), link);
|
||||
}
|
||||
}
|
||||
|
||||
public LanLinkProvider(Context context) {
|
||||
public LanLinkProvider(Context context)
|
||||
{
|
||||
this.context = context;
|
||||
onStart();
|
||||
}
|
||||
|
||||
private void setupUdpListener() {
|
||||
@ -413,7 +416,6 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
|
||||
}).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
//Log.i("KDE/LanLinkProvider", "onStart");
|
||||
if (!listening) {
|
||||
@ -428,11 +430,10 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNetworkChange() {
|
||||
public void refresh() {
|
||||
broadcastUdpPacket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
//Log.i("KDE/LanLinkProvider", "onStop");
|
||||
listening = false;
|
||||
@ -453,4 +454,9 @@ public class LanLinkProvider extends BaseLinkProvider implements LanLink.LinkDis
|
||||
return "LanLinkProvider";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(DeviceOffer offer) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ package org.kde.kdeconnect.Backends.LoopbackBackend;
|
||||
|
||||
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.BasePairingHandler;
|
||||
import org.kde.kdeconnect.Device;
|
||||
@ -30,7 +30,7 @@ import org.kde.kdeconnect.NetworkPacket;
|
||||
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
public class LoopbackLink extends BaseLink {
|
||||
public class LoopbackLink extends DeviceLink {
|
||||
|
||||
public LoopbackLink(Context context, BaseLinkProvider linkProvider) {
|
||||
super(context, "loopback", linkProvider);
|
||||
|
@ -23,6 +23,9 @@ package org.kde.kdeconnect.Backends.LoopbackBackend;
|
||||
import android.content.Context;
|
||||
|
||||
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;
|
||||
|
||||
public class LoopbackLinkProvider extends BaseLinkProvider {
|
||||
@ -34,25 +37,20 @@ public class LoopbackLinkProvider extends BaseLinkProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
onNetworkChange();
|
||||
public void connect(DeviceOffer offer) {
|
||||
onLinkConnected(offer, new LoopbackLink(context, this));
|
||||
}
|
||||
|
||||
@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
|
||||
public String getName() {
|
||||
return "LoopbackLinkProvider";
|
||||
|
@ -25,7 +25,7 @@ import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
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.Device;
|
||||
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
|
||||
@ -45,7 +45,7 @@ import java.nio.channels.NotYetConnectedException;
|
||||
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
public class MulticastLink extends BaseLink {
|
||||
public class MulticastLink extends DeviceLink {
|
||||
|
||||
static final String LOG_TAG = "MulticastLink";
|
||||
|
||||
@ -57,11 +57,6 @@ public class MulticastLink extends BaseLink {
|
||||
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 final LinkDisconnectedCallback callback;
|
||||
@ -77,13 +72,11 @@ public class MulticastLink extends BaseLink {
|
||||
}
|
||||
|
||||
//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;
|
||||
socket = newSocket;
|
||||
|
||||
this.connectionSource = connectionSource;
|
||||
|
||||
if (oldSocket != null) {
|
||||
oldSocket.close(); //This should cancel the readThread
|
||||
}
|
||||
@ -122,10 +115,10 @@ public class MulticastLink extends BaseLink {
|
||||
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);
|
||||
callback = linkProvider;
|
||||
reset(socket, connectionSource);
|
||||
reset(socket);
|
||||
}
|
||||
|
||||
|
||||
@ -255,14 +248,4 @@ public class MulticastLink extends BaseLink {
|
||||
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.SharedPreferences;
|
||||
import android.net.Network;
|
||||
import android.net.nsd.NsdManager;
|
||||
import android.net.nsd.NsdManager.RegistrationListener;
|
||||
import android.net.nsd.NsdManager.ResolveListener;
|
||||
import android.net.nsd.NsdServiceInfo;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Build;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.kde.kdeconnect.Backends.BaseLink;
|
||||
import org.kde.kdeconnect.Backends.DeviceLink;
|
||||
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
||||
import org.kde.kdeconnect.Backends.DeviceOffer;
|
||||
import org.kde.kdeconnect.BackgroundService;
|
||||
import org.kde.kdeconnect.Device;
|
||||
import org.kde.kdeconnect.Helpers.DeviceHelper;
|
||||
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
|
||||
import org.kde.kdeconnect.NetworkPacket;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.net.SocketFactory;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
/**
|
||||
@ -69,13 +65,13 @@ import javax.net.ssl.SSLSocket;
|
||||
*/
|
||||
public class MulticastLinkProvider extends BaseLinkProvider implements MulticastLink.LinkDisconnectedCallback {
|
||||
|
||||
HashMap<InetAddress, DeviceOffer> offers = new HashMap<>();
|
||||
|
||||
static final String LOG_TAG = "MulticastLink";
|
||||
|
||||
static final String SERVICE_TYPE = "_kdeconnect._tcp";
|
||||
|
||||
private NsdManager mNsdManager;
|
||||
private RegistrationListener mRegistrationListener;
|
||||
private boolean mServiceRegistered = false;
|
||||
|
||||
private final static int MIN_PORT = 1716;
|
||||
private final static int MAX_PORT = 1764;
|
||||
@ -89,31 +85,31 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
|
||||
|
||||
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
|
||||
public void linkDisconnected(MulticastLink brokenLink) {
|
||||
String deviceId = brokenLink.getDeviceId();
|
||||
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 void tcpPacketReceived(Socket socket) {
|
||||
|
||||
writeIdentity(socket);
|
||||
NetworkPacket otherIdentity = readIdentity(socket);
|
||||
|
||||
if (!otherIdentity.getType().equals(NetworkPacket.PACKET_TYPE_IDENTITY)) {
|
||||
Log.e(LOG_TAG, "Expecting an identity package instead of " + otherIdentity.getType());
|
||||
return;
|
||||
private InetAddress getDeviceIpAddress() {
|
||||
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
|
||||
WifiManager.MulticastLock lock = wifi.createMulticastLock("jmdns-multicast-lock");
|
||||
lock.setReferenceCounted(true);
|
||||
lock.acquire();
|
||||
InetAddress result = null;
|
||||
try {
|
||||
// figure out our wifi address, otherwise bail
|
||||
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) {
|
||||
try {
|
||||
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
|
||||
* {@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>
|
||||
* Called when a socket is connected.
|
||||
*
|
||||
* @param identityPacket identity of a 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
|
||||
*/
|
||||
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);
|
||||
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;
|
||||
}
|
||||
String deviceId = deviceOffer.id;
|
||||
|
||||
// If I'm the TCP server I will be the SSL client and viceversa.
|
||||
final boolean clientMode = (connectionStarted == MulticastLink.ConnectionStarted.Locally);
|
||||
|
||||
// Do the SSL handshake
|
||||
try {
|
||||
SharedPreferences preferences = context.getSharedPreferences("trusted_devices", Context.MODE_PRIVATE);
|
||||
boolean isDeviceTrusted = preferences.getBoolean(deviceId, false);
|
||||
|
||||
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);
|
||||
Log.i(LOG_TAG, "Starting SSL handshake with " + deviceOffer.name + " trusted:" + isDeviceTrusted);
|
||||
|
||||
final SSLSocket sslsocket = SslHelper.convertToSslSocket(context, socket, deviceId, isDeviceTrusted, clientMode);
|
||||
sslsocket.addHandshakeCompletedListener(event -> {
|
||||
String mode = clientMode ? "client" : "server";
|
||||
try {
|
||||
Certificate certificate = event.getPeerCertificates()[0];
|
||||
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);
|
||||
createLink(deviceOffer, sslsocket);
|
||||
} 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 -> {
|
||||
Device device = service.getDevice(deviceId);
|
||||
if (device == null) return;
|
||||
@ -188,7 +160,7 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
|
||||
sslsocket.startHandshake();
|
||||
}
|
||||
} 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();
|
||||
//for (String cipher : ciphers) {
|
||||
@ -207,7 +179,7 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
|
||||
* link is operated on at a time.
|
||||
* <p>
|
||||
* 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>
|
||||
*
|
||||
* @param identityPacket representation of remote device
|
||||
@ -215,53 +187,50 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
|
||||
* @param connectionOrigin which side started this connection
|
||||
* @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 {
|
||||
|
||||
String deviceId = identityPacket.getString("deviceId");
|
||||
private void createLink(DeviceOffer offer, SSLSocket socket) throws IOException {
|
||||
String deviceId = offer.id;
|
||||
MulticastLink currentLink = visibleComputers.get(deviceId);
|
||||
if (currentLink != null) {
|
||||
//Update old link
|
||||
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());
|
||||
} else {
|
||||
Log.i(LOG_TAG, "Creating a new link for device " + deviceId);
|
||||
//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);
|
||||
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) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
|
||||
}
|
||||
|
||||
private void setupTcpListener() {
|
||||
@ -276,14 +245,21 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
|
||||
try {
|
||||
Socket socket = tcpServer.accept();
|
||||
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) {
|
||||
Log.e(LOG_TAG, "TcpReceive exception", e);
|
||||
}
|
||||
}
|
||||
Log.w("TcpListener", "Stopping TCP listener");
|
||||
}).start();
|
||||
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public void initializeRegistrationListener() {
|
||||
mRegistrationListener = new NsdManager.RegistrationListener() {
|
||||
NsdManager.RegistrationListener mRegistrationListener = new NsdManager.RegistrationListener() {
|
||||
|
||||
@Override
|
||||
public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) {
|
||||
// Save the service name. Android may have changed it in order to
|
||||
// resolve a conflict, so update the name you initially requested
|
||||
// with the name Android actually used.
|
||||
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;
|
||||
@Override
|
||||
public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) {
|
||||
// Save the service name. Android may have changed it in order to
|
||||
// resolve a conflict, so update the name you initially requested
|
||||
// with the name Android actually used.
|
||||
Log.i(LOG_TAG, "Registered " + NsdServiceInfo.getServiceName());
|
||||
}
|
||||
mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
|
||||
try {
|
||||
mNsdManager.unregisterService(registrationListener);
|
||||
} catch (java.lang.IllegalArgumentException e) {
|
||||
// not yet registered, but it's fine.
|
||||
|
||||
@Override
|
||||
public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
|
||||
// Registration failed! Put debugging code here to determine why.
|
||||
Log.e(LOG_TAG, "Registration failed");
|
||||
}
|
||||
NsdServiceInfo serviceInfo = new NsdServiceInfo();
|
||||
|
||||
// The name is subject to change based on conflicts
|
||||
// with other services advertised on the same network.
|
||||
NetworkPacket myIdentity = NetworkPacket.createIdentityPacket(context);
|
||||
String did = myIdentity.getString("deviceID");
|
||||
String name = myIdentity.getString("deviceName");
|
||||
InetAddress addr = this.tcpServer.getInetAddress();
|
||||
int port = this.tcpServer.getLocalPort();
|
||||
@Override
|
||||
public void onServiceUnregistered(NsdServiceInfo serviceInfo) {
|
||||
// Service has been unregistered. This only happens when you call
|
||||
// NsdManager.unregisterService() and pass in this listener.
|
||||
|
||||
// These cause the requirement for api level 21.
|
||||
serviceInfo.setAttribute("name", myIdentity.getString("deviceName"));
|
||||
serviceInfo.setAttribute("id", myIdentity.getString("deviceId"));
|
||||
serviceInfo.setAttribute("type", myIdentity.getString("deviceType"));
|
||||
serviceInfo.setAttribute("version", myIdentity.getString("protocolVersion"));
|
||||
Log.e(LOG_TAG, "Service unregistered: " + serviceInfo);
|
||||
offers.remove(serviceInfo.getHost());
|
||||
}
|
||||
|
||||
// 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 " + 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);
|
||||
}
|
||||
@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(api = Build.VERSION_CODES.JELLY_BEAN)
|
||||
public ResolveListener createResolveListener() {
|
||||
@ -387,120 +322,134 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
|
||||
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) {
|
||||
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();
|
||||
int remotePort = serviceInfo.getPort();
|
||||
|
||||
SocketFactory socketFactory = SocketFactory.getDefault();
|
||||
Socket socket;
|
||||
try {
|
||||
socket = socketFactory.createSocket(hostname, remotePort);
|
||||
} catch (IOException e) {
|
||||
Log.e(LOG_TAG, "Unable to open socket to mDNS remote: " + serviceInfo, e);
|
||||
return;
|
||||
}
|
||||
DeviceOffer offer = new DeviceOffer();
|
||||
offer.id = id;
|
||||
offer.name = name;
|
||||
offer.type = type;
|
||||
offer.protocolVersion = protocolVersion;
|
||||
offer.host = hostname;
|
||||
offer.port = remotePort;
|
||||
offer.provider = MulticastLinkProvider.this;
|
||||
|
||||
writeIdentity(socket);
|
||||
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;
|
||||
}
|
||||
offers.put(hostname, offer);
|
||||
onOfferAdded(offer);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@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.
|
||||
@Override
|
||||
public void onDiscoveryStarted(String regType) {
|
||||
Log.d(LOG_TAG, "Service discovery started");
|
||||
}
|
||||
NsdManager.DiscoveryListener discoveryListener = new NsdManager.DiscoveryListener() {
|
||||
|
||||
@Override
|
||||
public void onServiceFound(NsdServiceInfo service) {
|
||||
// A service was found! Do something with it.
|
||||
Log.d(LOG_TAG, "Service discovery success" + service);
|
||||
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;
|
||||
// Called as soon as service discovery begins.
|
||||
@Override
|
||||
public void onDiscoveryStarted(String regType) {
|
||||
Log.e(LOG_TAG, "Service discovery started");
|
||||
}
|
||||
|
||||
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 onServiceFound(NsdServiceInfo service) {
|
||||
// A service was found! Do something with it.
|
||||
Log.e(LOG_TAG, "Service discovery success " + service);
|
||||
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.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
|
||||
public void onNetworkChange() {
|
||||
public void refresh() {
|
||||
onStop();
|
||||
onStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
// This backend does not work on older Android versions
|
||||
return;
|
||||
public synchronized void onStart() {
|
||||
Log.e(LOG_TAG,"ON_START");
|
||||
if (!listening) {
|
||||
Log.e(LOG_TAG,"ON_START doing things");
|
||||
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);
|
||||
tcpServer.close();
|
||||
listening = false;
|
||||
public synchronized void onStop() {
|
||||
/*Log.e(LOG_TAG,"ON_STOP");
|
||||
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
|
||||
@ -508,4 +457,29 @@ public class MulticastLinkProvider extends BaseLinkProvider implements Multicast
|
||||
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.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.DeviceOffer;
|
||||
import org.kde.kdeconnect.Backends.LanBackend.LanLinkProvider;
|
||||
import org.kde.kdeconnect.Backends.MulticastBackend.MulticastLinkProvider;
|
||||
import org.kde.kdeconnect.Helpers.NotificationHelper;
|
||||
@ -83,6 +84,7 @@ public class BackgroundService extends Service {
|
||||
private final ArrayList<BaseLinkProvider> linkProviders = new ArrayList<>();
|
||||
|
||||
private final ConcurrentHashMap<String, Device> devices = new ConcurrentHashMap<>();
|
||||
private final ConcurrentHashMap<String, DeviceOffer> deviceOffers = new ConcurrentHashMap<>();
|
||||
|
||||
private final HashSet<Object> discoveryModeAcquisitions = new HashSet<>();
|
||||
|
||||
@ -100,19 +102,6 @@ public class BackgroundService extends Service {
|
||||
return wasEmpty;
|
||||
}
|
||||
|
||||
private void releaseDiscoveryMode(Object key) {
|
||||
boolean removed = discoveryModeAcquisitions.remove(key);
|
||||
//Log.e("releaseDiscoveryMode",key.getClass().getName() +" ["+discoveryModeAcquisitions.size()+"]");
|
||||
if (removed && discoveryModeAcquisitions.isEmpty()) {
|
||||
cleanDevices();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInDiscoveryMode() {
|
||||
//return !discoveryModeAcquisitions.isEmpty();
|
||||
return true; // Keep it always on for now
|
||||
}
|
||||
|
||||
private final Device.PairingCallback devicePairingCallback = new Device.PairingCallback() {
|
||||
@Override
|
||||
public void incomingRequest() {
|
||||
@ -163,7 +152,7 @@ public class BackgroundService extends Service {
|
||||
}
|
||||
|
||||
private void registerLinkProviders() {
|
||||
linkProviders.add(new LanLinkProvider(this));
|
||||
//linkProviders.add(new LanLinkProvider(this));
|
||||
linkProviders.add(new MulticastLinkProvider(this));
|
||||
// linkProviders.add(new LoopbackLinkProvider(this));
|
||||
// linkProviders.add(new BluetoothLinkProvider(this));
|
||||
@ -177,46 +166,55 @@ public class BackgroundService extends Service {
|
||||
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() {
|
||||
|
||||
@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);
|
||||
|
||||
if (device != null) {
|
||||
Log.i("KDE/BackgroundService", "addLink, known device: " + deviceId);
|
||||
device.addLink(identityPacket, link);
|
||||
} else {
|
||||
Log.i("KDE/BackgroundService", "addLink,unknown device: " + deviceId);
|
||||
device = new Device(BackgroundService.this, identityPacket, link);
|
||||
if (device.isPaired() || device.isPairRequested() || device.isPairRequestedByPeer()
|
||||
|| link.linkShouldBeKeptAlive()
|
||||
|| isInDiscoveryMode()) {
|
||||
devices.put(deviceId, device);
|
||||
device.addPairingCallback(devicePairingCallback);
|
||||
} else {
|
||||
device.disconnect();
|
||||
}
|
||||
// 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 onConnectionLost(BaseLink link) {
|
||||
Device d = devices.get(link.getDeviceId());
|
||||
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);
|
||||
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());
|
||||
if (d != null) {
|
||||
d.removeLink(link);
|
||||
@ -230,6 +228,12 @@ public class BackgroundService extends Service {
|
||||
}
|
||||
onDeviceListChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionFailed(DeviceOffer offer, String reason) {
|
||||
Log.e("KDE/BackgroundService", "device connect failed: " + reason);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
public ConcurrentHashMap<String, Device> getDevices() {
|
||||
@ -237,8 +241,15 @@ public class BackgroundService extends Service {
|
||||
}
|
||||
|
||||
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) {
|
||||
a.onNetworkChange();
|
||||
a.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,7 +301,7 @@ public class BackgroundService extends Service {
|
||||
addConnectionListener(deviceListener);
|
||||
|
||||
for (BaseLinkProvider a : linkProviders) {
|
||||
a.onStart();
|
||||
a.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@ -402,9 +413,10 @@ public class BackgroundService extends Service {
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
stopForeground(true);
|
||||
/*
|
||||
for (BaseLinkProvider a : linkProviders) {
|
||||
a.onStop();
|
||||
}
|
||||
}*/
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
|
@ -41,11 +41,11 @@ import androidx.core.content.ContextCompat;
|
||||
|
||||
import org.apache.commons.collections4.MultiValuedMap;
|
||||
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.DeviceOffer;
|
||||
import org.kde.kdeconnect.Helpers.DeviceHelper;
|
||||
import org.kde.kdeconnect.Helpers.NotificationHelper;
|
||||
import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper;
|
||||
import org.kde.kdeconnect.Plugins.Plugin;
|
||||
import org.kde.kdeconnect.Plugins.PluginFactory;
|
||||
import org.kde.kdeconnect.UserInterface.MainActivity;
|
||||
@ -66,7 +66,7 @@ import java.util.Vector;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
public class Device implements BaseLink.PacketReceiver {
|
||||
public class Device implements DeviceLink.PacketReceiver {
|
||||
|
||||
private final Context context;
|
||||
|
||||
@ -82,7 +82,7 @@ public class Device implements BaseLink.PacketReceiver {
|
||||
private final CopyOnWriteArrayList<PairingCallback> pairingCallback = new CopyOnWriteArrayList<>();
|
||||
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 List<String> supportedPlugins = new ArrayList<>();
|
||||
@ -170,21 +170,28 @@ public class Device implements BaseLink.PacketReceiver {
|
||||
//reloadPluginsFromSettings();
|
||||
}
|
||||
|
||||
//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, NetworkPacket np, BaseLink dl) {
|
||||
|
||||
//Log.e("Device","Constructor B");
|
||||
//Remembered trusted device, we need to wait for a incoming devicelink to communicate
|
||||
Device(Context context, DeviceOffer deviceOffer, PairStatus paired) {
|
||||
settings = context.getSharedPreferences(deviceOffer.id, Context.MODE_PRIVATE);
|
||||
|
||||
Log.e("AAAAA", "Adding device "+deviceOffer.name);
|
||||
this.context = context;
|
||||
this.deviceId = np.getString("deviceId");
|
||||
this.name = context.getString(R.string.unknown_device); //We read it in addLink
|
||||
this.pairStatus = PairStatus.NotPaired;
|
||||
this.protocolVersion = 0;
|
||||
this.deviceType = DeviceType.Computer;
|
||||
this.deviceId = deviceOffer.id;
|
||||
this.name = deviceOffer.name;
|
||||
this.pairStatus = paired;
|
||||
this.protocolVersion = deviceOffer.protocolVersion;
|
||||
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() {
|
||||
@ -434,7 +441,7 @@ public class Device implements BaseLink.PacketReceiver {
|
||||
return !links.isEmpty();
|
||||
}
|
||||
|
||||
public void addLink(NetworkPacket identityPacket, BaseLink link) {
|
||||
public void addLink(DeviceLink link) {
|
||||
if (links.isEmpty()) {
|
||||
packetQueue = new DevicePacketQueue(this);
|
||||
}
|
||||
@ -442,31 +449,6 @@ public class Device implements BaseLink.PacketReceiver {
|
||||
links.add(link);
|
||||
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 {
|
||||
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.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())) {
|
||||
BasePairingHandler.PairingHandlerCallback callback = new BasePairingHandler.PairingHandlerCallback() {
|
||||
@ -508,11 +490,10 @@ public class Device implements BaseLink.PacketReceiver {
|
||||
pairingHandlers.put(link.getName(), link.getPairingHandler(this, callback));
|
||||
}
|
||||
|
||||
Set<String> outgoingCapabilities = identityPacket.getStringSet("outgoingCapabilities", null);
|
||||
Set<String> incomingCapabilities = identityPacket.getStringSet("incomingCapabilities", null);
|
||||
Set<String> outgoingCapabilities = new HashSet<>();
|
||||
Set<String> incomingCapabilities = new HashSet<>();
|
||||
|
||||
|
||||
if (incomingCapabilities != null && outgoingCapabilities != null) {
|
||||
if (!incomingCapabilities.isEmpty() && !outgoingCapabilities.isEmpty()) {
|
||||
supportedPlugins = new Vector<>(PluginFactory.pluginsForCapabilities(incomingCapabilities, outgoingCapabilities));
|
||||
} else {
|
||||
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();
|
||||
|
||||
/* Remove pairing handler corresponding to that link too if it was the only link*/
|
||||
boolean linkPresent = false;
|
||||
for (BaseLink bl : links) {
|
||||
for (DeviceLink bl : links) {
|
||||
if (bl.getName().equals(link.getName())) {
|
||||
linkPresent = true;
|
||||
break;
|
||||
@ -540,7 +521,7 @@ public class Device implements BaseLink.PacketReceiver {
|
||||
|
||||
link.removePacketReceiver(this);
|
||||
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()) {
|
||||
reloadPluginsFromSettings();
|
||||
if (packetQueue != null) {
|
||||
@ -689,7 +670,7 @@ public class Device implements BaseLink.PacketReceiver {
|
||||
* @param np the packet to send
|
||||
* @param callback a callback that can receive realtime updates
|
||||
* @return true if the packet was sent ok, false otherwise
|
||||
* @see BaseLink#sendPacket(NetworkPacket, SendPacketStatusCallback)
|
||||
* @see DeviceLink#sendPacket(NetworkPacket, SendPacketStatusCallback)
|
||||
*/
|
||||
@WorkerThread
|
||||
public boolean sendPacketBlocking(final NetworkPacket np, final SendPacketStatusCallback callback) {
|
||||
@ -703,7 +684,7 @@ public class Device implements BaseLink.PacketReceiver {
|
||||
|
||||
boolean success = false;
|
||||
//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)
|
||||
continue; //Since we made a copy, maybe somebody destroyed the link in the meanwhile
|
||||
success = link.sendPacket(np, callback);
|
||||
@ -880,27 +861,10 @@ public class Device implements BaseLink.PacketReceiver {
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
for (BaseLink link : links) {
|
||||
for (DeviceLink link : links) {
|
||||
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() {
|
||||
return supportedPlugins;
|
||||
}
|
||||
|
@ -51,11 +51,11 @@ import androidx.core.content.ContextCompat;
|
||||
import androidx.core.graphics.drawable.DrawableCompat;
|
||||
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.DeviceOffer;
|
||||
import org.kde.kdeconnect.BackgroundService;
|
||||
import org.kde.kdeconnect.Helpers.VideoUrlsHelper;
|
||||
import org.kde.kdeconnect.NetworkPacket;
|
||||
import org.kde.kdeconnect.Plugins.SystemvolumePlugin.SystemvolumeFragment;
|
||||
import org.kde.kdeconnect.UserInterface.ThemeUtil;
|
||||
import org.kde.kdeconnect_tp.R;
|
||||
@ -237,15 +237,32 @@ public class MprisActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
private final BaseLinkProvider.ConnectionReceiver connectionReceiver = new BaseLinkProvider.ConnectionReceiver() {
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionLost(BaseLink link) {
|
||||
public void onConnectionFailed(DeviceOffer offer, String reason) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLinkDisconnected(DeviceLink link) {
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@Override
|
||||
|
Loading…
x
Reference in New Issue
Block a user