mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-09-04 08:05:10 +00:00
Reimplemented pairing handler interface, now it it is similar to kde version
This commit is contained in:
@@ -44,6 +44,10 @@ public abstract class BaseLink {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
/* To be implemented by each link for pairing handlers */
|
||||
public abstract String getName();
|
||||
public abstract BasePairingHandler getPairingHandler(Device device, BasePairingHandler.PairingHandlerCallback callback);
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
@@ -23,14 +23,70 @@ package org.kde.kdeconnect.Backends;
|
||||
import org.kde.kdeconnect.Device;
|
||||
import org.kde.kdeconnect.NetworkPackage;
|
||||
|
||||
public interface BasePairingHandler {
|
||||
import java.util.Timer;
|
||||
|
||||
NetworkPackage createPairPackage(Device device);
|
||||
void packageReceived(Device device, NetworkPackage np) throws Exception;
|
||||
void requestPairing(Device device, Device.SendPackageStatusCallback callback);
|
||||
void acceptPairing(Device device, Device.SendPackageStatusCallback callback);
|
||||
void rejectPairing(Device device);
|
||||
void pairingDone(Device device);
|
||||
void unpair(Device device);
|
||||
/**
|
||||
* This class separates the pairing interface for each type of link.
|
||||
* Since different links can pair via different methods, like for LanLink certificate and public key should be shared,
|
||||
* for Bluetooth link they should be paired via bluetooth etc.
|
||||
* Each "Device" instance maintains a hash map for these pairing handlers so that there can be single pairing handler per
|
||||
* per link type per device.
|
||||
* Pairing handler keeps information about device, latest link, and pair status of the link
|
||||
* During first pairing process, the pairing process is nearly same as old process.
|
||||
* After that if any one of the link is paired, then we can say that device is paired, so new link will pair automatically
|
||||
*/
|
||||
|
||||
public abstract class BasePairingHandler {
|
||||
|
||||
protected enum PairStatus{
|
||||
NotPaired,
|
||||
Requested,
|
||||
RequestedByPeer,
|
||||
Paired
|
||||
}
|
||||
|
||||
public interface PairingHandlerCallback {
|
||||
void incomingRequest();
|
||||
void pairingDone();
|
||||
void pairingFailed(String error);
|
||||
void unpaired();
|
||||
}
|
||||
|
||||
|
||||
protected Device mDevice;
|
||||
protected BaseLink mBaseLink;
|
||||
protected PairStatus mPairStatus;
|
||||
protected PairingHandlerCallback mCallback;
|
||||
protected Timer mPairingTimer;
|
||||
|
||||
public BasePairingHandler(Device device, PairingHandlerCallback callback) {
|
||||
this.mDevice = device;
|
||||
this.mCallback = callback;
|
||||
}
|
||||
|
||||
public void setLink(BaseLink baseLink) {
|
||||
this.mBaseLink = baseLink;
|
||||
}
|
||||
|
||||
public boolean isPaired() {
|
||||
return mPairStatus == PairStatus.Paired;
|
||||
}
|
||||
|
||||
public boolean isPairRequested() {
|
||||
return mPairStatus == PairStatus.Requested;
|
||||
}
|
||||
|
||||
public boolean isPairRequestedByPeer() {
|
||||
return mPairStatus == PairStatus.RequestedByPeer;
|
||||
}
|
||||
|
||||
/* To be implemented by respective pairing handler */
|
||||
public abstract NetworkPackage createPairPackage();
|
||||
public abstract void packageReceived(NetworkPackage np) throws Exception;
|
||||
public abstract void requestPairing();
|
||||
public abstract void acceptPairing();
|
||||
public abstract void rejectPairing();
|
||||
public abstract void pairingDone();
|
||||
public abstract void unpair();
|
||||
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ import android.util.Log;
|
||||
import org.json.JSONObject;
|
||||
import org.kde.kdeconnect.Backends.BaseLink;
|
||||
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
||||
import org.kde.kdeconnect.Backends.BasePairingHandler;
|
||||
import org.kde.kdeconnect.BackgroundService;
|
||||
import org.kde.kdeconnect.Device;
|
||||
import org.kde.kdeconnect.Helpers.SecurityHelpers.RsaHelper;
|
||||
@@ -40,7 +41,9 @@ import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.nio.channels.NotYetConnectedException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
@@ -80,6 +83,16 @@ public class LanLink extends BaseLink {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "LanLink";
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasePairingHandler getPairingHandler(Device device, BasePairingHandler.PairingHandlerCallback callback) {
|
||||
return new LanPairingHandler(device, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPackageReceiver(PackageReceiver pr) {
|
||||
super.addPackageReceiver(pr);
|
||||
@@ -91,7 +104,7 @@ public class LanLink extends BaseLink {
|
||||
if (!device.isPaired()) return;
|
||||
// If the device is already paired due to other link, just send a pairing request to get required attributes for this link
|
||||
if (device.publicKey == null) {
|
||||
getLinkProvider().getPairingHandler().requestPairing(device, null);
|
||||
device.requestPairing();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@@ -416,8 +416,6 @@ public class LanLinkProvider extends BaseLinkProvider {
|
||||
|
||||
clientGroup = new NioEventLoopGroup();
|
||||
|
||||
pairingHandler = new LanPairingHandler();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -26,9 +26,7 @@ import android.preference.PreferenceManager;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
||||
import org.kde.kdeconnect.Backends.BasePairingHandler;
|
||||
import org.kde.kdeconnect.BackgroundService;
|
||||
import org.kde.kdeconnect.Device;
|
||||
import org.kde.kdeconnect.NetworkPackage;
|
||||
import org.kde.kdeconnect_tp.R;
|
||||
@@ -36,71 +34,202 @@ import org.kde.kdeconnect_tp.R;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
public class LanPairingHandler implements BasePairingHandler {
|
||||
public class LanPairingHandler extends BasePairingHandler {
|
||||
|
||||
public LanPairingHandler(Device device, final PairingHandlerCallback callback) {
|
||||
super(device, callback);
|
||||
|
||||
if (device.isPaired()) {
|
||||
if (device.publicKey != null) {
|
||||
mPairStatus = PairStatus.Paired;
|
||||
} else {
|
||||
/* Request pairing if device is paired but public key is not there */
|
||||
requestPairing();
|
||||
}
|
||||
} else {
|
||||
mPairStatus = PairStatus.NotPaired;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetworkPackage createPairPackage(Device device) {
|
||||
public NetworkPackage createPairPackage() {
|
||||
NetworkPackage np = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_PAIR);
|
||||
np.set("pair", true);
|
||||
SharedPreferences globalSettings = PreferenceManager.getDefaultSharedPreferences(device.getContext());
|
||||
np.set("link", mBaseLink.getName());
|
||||
SharedPreferences globalSettings = PreferenceManager.getDefaultSharedPreferences(mDevice.getContext());
|
||||
String publicKey = "-----BEGIN PUBLIC KEY-----\n" + globalSettings.getString("publicKey", "").trim()+ "\n-----END PUBLIC KEY-----\n";
|
||||
np.set("publicKey", publicKey);
|
||||
return np;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void packageReceived(Device device, NetworkPackage np) throws Exception{
|
||||
public void packageReceived(NetworkPackage np) throws Exception{
|
||||
|
||||
if (!np.getString("link").equals(mBaseLink.getName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean wantsPair = np.getBoolean("pair");
|
||||
|
||||
Log.e("KDE/LPHPackageReceived", "Wants pair " + wantsPair + ", isPaired " + isPaired() );
|
||||
|
||||
if (wantsPair == isPaired()) {
|
||||
if (mPairStatus == PairStatus.Requested) {
|
||||
//Log.e("Device","Unpairing (pair rejected)");
|
||||
mPairStatus = PairStatus.NotPaired;
|
||||
if (mPairingTimer != null) mPairingTimer.cancel();
|
||||
mCallback.pairingFailed(mDevice.getContext().getString(R.string.error_canceled_by_other_peer));
|
||||
return;
|
||||
} else if (mPairStatus == PairStatus.Paired) {
|
||||
/**
|
||||
* If wants pair is true and is paired is true, this means other device is trying to pair again, might be because it unpaired this device somehow
|
||||
* and we don't know it, unpair it internally
|
||||
*/
|
||||
mCallback.unpaired();
|
||||
}
|
||||
}
|
||||
|
||||
if (wantsPair) {
|
||||
|
||||
//Retrieve their public key
|
||||
try {
|
||||
String publicKeyContent = np.getString("publicKey").replace("-----BEGIN PUBLIC KEY-----\n","").replace("-----END PUBLIC KEY-----\n", "");
|
||||
byte[] publicKeyBytes = Base64.decode(publicKeyContent, 0);
|
||||
device.publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(publicKeyBytes));
|
||||
mDevice.publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(publicKeyBytes));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e("KDE/Device","Pairing exception: Received incorrect key");
|
||||
throw e;
|
||||
}
|
||||
mCallback.pairingFailed(mDevice.getContext().getString(R.string.error_invalid_key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestPairing(Device device, Device.SendPackageStatusCallback callback) {
|
||||
if (callback == null) {
|
||||
device.sendPackage(createPairPackage(device));
|
||||
if (mPairStatus == PairStatus.Requested) { //We started pairing
|
||||
|
||||
Log.i("KDE/Pairing","Pair answer");
|
||||
|
||||
if (mPairingTimer != null) mPairingTimer.cancel();
|
||||
|
||||
pairingDone();
|
||||
|
||||
} else {
|
||||
device.sendPackage(createPairPackage(device), callback);
|
||||
}
|
||||
|
||||
Log.i("KDE/Pairing", "Pair request");
|
||||
|
||||
/**
|
||||
* If device is already paired, accept pairing silently
|
||||
*/
|
||||
if (mDevice.isPaired()) {
|
||||
acceptPairing();
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pairing notifications are still managed by device as there is no other way to know about notificationId to cancel notification when PairActivity is started
|
||||
* Even putting notificationId in intent does not work because PairActivity can be started from MainActivity too, so then notificationId cannot be set
|
||||
*/
|
||||
mDevice.displayPairingNotification();
|
||||
|
||||
if (mPairingTimer != null) mPairingTimer.cancel();
|
||||
mPairingTimer = new Timer();
|
||||
|
||||
mPairingTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void acceptPairing(Device device, Device.SendPackageStatusCallback callback) {
|
||||
if (callback == null) {
|
||||
device.sendPackage(createPairPackage(device));
|
||||
public void run() {
|
||||
Log.e("KDE/Device","Unpairing (timeout B)");
|
||||
mPairStatus = PairStatus.NotPaired;
|
||||
|
||||
mDevice.cancelPairingNotification();
|
||||
}
|
||||
}, 25*1000); //Time to show notification, waiting for user to accept (peer will timeout in 30 seconds)
|
||||
mPairStatus = PairStatus.RequestedByPeer;
|
||||
mCallback.incomingRequest();
|
||||
|
||||
}
|
||||
} else {
|
||||
device.sendPackage(createPairPackage(device), callback);
|
||||
Log.i("KDE/Pairing", "Unpair request");
|
||||
|
||||
if (mPairStatus == PairStatus.Requested) {
|
||||
if (mPairingTimer != null) mPairingTimer.cancel();
|
||||
mCallback.pairingFailed(mDevice.getContext().getString(R.string.error_canceled_by_other_peer));
|
||||
} else if (mPairStatus == PairStatus.Paired) {
|
||||
mCallback.unpaired();
|
||||
}
|
||||
|
||||
mPairStatus = PairStatus.NotPaired;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rejectPairing(Device device) {
|
||||
public void requestPairing() {
|
||||
|
||||
Device.SendPackageStatusCallback statusCallback = new Device.SendPackageStatusCallback() {
|
||||
@Override
|
||||
protected void onSuccess() {
|
||||
if (mPairingTimer != null) mPairingTimer.cancel();
|
||||
mPairingTimer = new Timer();
|
||||
mPairingTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
mCallback.pairingFailed(mDevice.getContext().getString(R.string.error_timed_out));
|
||||
Log.e("KDE/Device","Unpairing (timeout A)");
|
||||
mPairStatus = PairStatus.NotPaired;
|
||||
}
|
||||
}, 30*1000); //Time to wait for the other to accept
|
||||
mPairStatus = PairStatus.Requested;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFailure(Throwable e) {
|
||||
mCallback.pairingFailed(mDevice.getContext().getString(R.string.error_could_not_send_package));
|
||||
}
|
||||
};
|
||||
mDevice.sendPackage(createPairPackage(), statusCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptPairing() {
|
||||
if (mPairingTimer != null) mPairingTimer.cancel();
|
||||
Device.SendPackageStatusCallback statusCallback = new Device.SendPackageStatusCallback() {
|
||||
@Override
|
||||
protected void onSuccess() {
|
||||
pairingDone();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFailure(Throwable e) {
|
||||
mCallback.pairingFailed(mDevice.getContext().getString(R.string.error_not_reachable));
|
||||
}
|
||||
};
|
||||
mDevice.sendPackage(createPairPackage(), statusCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rejectPairing() {
|
||||
if (mPairingTimer != null) mPairingTimer.cancel();
|
||||
mPairStatus = PairStatus.NotPaired;
|
||||
NetworkPackage np = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_PAIR);
|
||||
np.set("pair", false);
|
||||
device.sendPackage(np);
|
||||
np.set("link", mBaseLink.getName());
|
||||
mDevice.sendPackage(np);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pairingDone(Device device) {
|
||||
public void pairingDone() {
|
||||
// Store device information needed to create a Device object in a future
|
||||
SharedPreferences.Editor editor = device.getContext().getSharedPreferences(device.getDeviceId(), Context.MODE_PRIVATE).edit();
|
||||
Log.e("KDE/PairingDone", "Pairing Done");
|
||||
SharedPreferences.Editor editor = mDevice.getContext().getSharedPreferences(mDevice.getDeviceId(), Context.MODE_PRIVATE).edit();
|
||||
|
||||
try {
|
||||
String encodedPublicKey = Base64.encodeToString(device.publicKey.getEncoded(), 0);
|
||||
String encodedPublicKey = Base64.encodeToString(mDevice.publicKey.getEncoded(), 0);
|
||||
editor.putString("publicKey", encodedPublicKey);
|
||||
} catch (Exception e) {
|
||||
Log.e("KDE/PairingDone", "Error encoding public key");
|
||||
}
|
||||
|
||||
try {
|
||||
String encodedCertificate = Base64.encodeToString(device.certificate.getEncoded(), 0);
|
||||
String encodedCertificate = Base64.encodeToString(mDevice.certificate.getEncoded(), 0);
|
||||
editor.putString("certificate", encodedCertificate);
|
||||
} catch (NullPointerException n) {
|
||||
Log.e("KDE/PairingDone", "Certificate is null, remote device does not support ssl");
|
||||
@@ -112,12 +241,17 @@ public class LanPairingHandler implements BasePairingHandler {
|
||||
}
|
||||
editor.apply();
|
||||
|
||||
mPairStatus = PairStatus.Paired;
|
||||
mCallback.pairingDone();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unpair(Device device) {
|
||||
public void unpair() {
|
||||
mPairStatus = PairStatus.NotPaired;
|
||||
NetworkPackage np = new NetworkPackage(NetworkPackage.PACKAGE_TYPE_PAIR);
|
||||
np.set("pair", false);
|
||||
device.sendPackage(np);
|
||||
np.set("link", mBaseLink.getName());
|
||||
mDevice.sendPackage(np);
|
||||
}
|
||||
}
|
||||
|
@@ -24,11 +24,13 @@ import android.content.Context;
|
||||
|
||||
import org.kde.kdeconnect.Backends.BaseLink;
|
||||
import org.kde.kdeconnect.Backends.BaseLinkProvider;
|
||||
import org.kde.kdeconnect.Backends.BasePairingHandler;
|
||||
import org.kde.kdeconnect.Device;
|
||||
import org.kde.kdeconnect.Helpers.SecurityHelpers.RsaHelper;
|
||||
import org.kde.kdeconnect.NetworkPackage;
|
||||
|
||||
import java.security.PublicKey;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class LoopbackLink extends BaseLink {
|
||||
|
||||
@@ -36,6 +38,16 @@ public class LoopbackLink extends BaseLink {
|
||||
super(context, "loopback", linkProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "LoopbackLink";
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasePairingHandler getPairingHandler(Device device, BasePairingHandler.PairingHandlerCallback callback) {
|
||||
return new LoopbackPairingHandler(device, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPackage(NetworkPackage in, Device.SendPackageStatusCallback callback) {
|
||||
sendPackageEncrypted(in, callback, null);
|
||||
|
@@ -31,7 +31,6 @@ public class LoopbackLinkProvider extends BaseLinkProvider {
|
||||
|
||||
public LoopbackLinkProvider(Context context) {
|
||||
this.context = context;
|
||||
pairingHandler = new LoopbackPairingHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -21,7 +21,12 @@
|
||||
package org.kde.kdeconnect.Backends.LoopbackBackend;
|
||||
|
||||
import org.kde.kdeconnect.Backends.LanBackend.LanPairingHandler;
|
||||
import org.kde.kdeconnect.Device;
|
||||
|
||||
public class LoopbackPairingHandler extends LanPairingHandler{
|
||||
|
||||
public LoopbackPairingHandler(Device device, PairingHandlerCallback callback) {
|
||||
super(device, callback);
|
||||
}
|
||||
// Extending from LanPairingHandler, as it is similar to it
|
||||
}
|
||||
|
@@ -36,6 +36,7 @@ import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import org.kde.kdeconnect.Backends.BaseLink;
|
||||
import org.kde.kdeconnect.Backends.BasePairingHandler;
|
||||
import org.kde.kdeconnect.Plugins.Plugin;
|
||||
import org.kde.kdeconnect.Plugins.PluginFactory;
|
||||
import org.kde.kdeconnect.UserInterface.PairActivity;
|
||||
@@ -52,9 +53,8 @@ import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
public class Device implements BaseLink.PackageReceiver {
|
||||
|
||||
@@ -69,8 +69,6 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
|
||||
public enum PairStatus {
|
||||
NotPaired,
|
||||
Requested,
|
||||
RequestedByPeer,
|
||||
Paired
|
||||
}
|
||||
|
||||
@@ -94,16 +92,16 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
}
|
||||
|
||||
public interface PairingCallback {
|
||||
abstract void incomingRequest();
|
||||
abstract void pairingSuccessful();
|
||||
abstract void pairingFailed(String error);
|
||||
abstract void unpaired();
|
||||
void incomingRequest();
|
||||
void pairingSuccessful();
|
||||
void pairingFailed(String error);
|
||||
void unpaired();
|
||||
}
|
||||
|
||||
private DeviceType deviceType;
|
||||
private PairStatus pairStatus;
|
||||
private ArrayList<PairingCallback> pairingCallback = new ArrayList<PairingCallback>();
|
||||
private Timer pairingTimer;
|
||||
private Map<String, BasePairingHandler> pairingHandlers = new HashMap<String, BasePairingHandler>();
|
||||
|
||||
private final ArrayList<BaseLink> links = new ArrayList<BaseLink>();
|
||||
private final HashMap<String, Plugin> plugins = new HashMap<String, Plugin>();
|
||||
@@ -196,16 +194,31 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
return pairStatus == PairStatus.Paired;
|
||||
}
|
||||
|
||||
/* Asks all pairing handlers that, is pair requested? */
|
||||
public boolean isPairRequested() {
|
||||
return pairStatus == PairStatus.Requested;
|
||||
boolean pairRequested = false;
|
||||
for (BasePairingHandler ph: pairingHandlers.values()) {
|
||||
pairRequested = pairRequested || ph.isPairRequested();
|
||||
}
|
||||
return pairRequested;
|
||||
}
|
||||
|
||||
/* Asks all pairing handlers that, is pair requested by peer? */
|
||||
public boolean isPairRequestedByPeer() {
|
||||
boolean pairRequestedByPeer = false;
|
||||
for (BasePairingHandler ph : pairingHandlers.values()) {
|
||||
pairRequestedByPeer = pairRequestedByPeer || ph.isPairRequestedByPeer();
|
||||
}
|
||||
return pairRequestedByPeer;
|
||||
}
|
||||
|
||||
public void addPairingCallback(PairingCallback callback) {
|
||||
pairingCallback.add(callback);
|
||||
if (pairStatus == PairStatus.RequestedByPeer) {
|
||||
if (isPairRequestedByPeer()) {
|
||||
callback.incomingRequest();
|
||||
}
|
||||
}
|
||||
|
||||
public void removePairingCallback(PairingCallback callback) {
|
||||
pairingCallback.remove(callback);
|
||||
}
|
||||
@@ -220,15 +233,6 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
cb.pairingFailed(res.getString(R.string.error_already_paired));
|
||||
}
|
||||
return;
|
||||
case Requested:
|
||||
for (PairingCallback cb : pairingCallback) {
|
||||
cb.pairingFailed(res.getString(R.string.error_already_requested));
|
||||
}
|
||||
return;
|
||||
case RequestedByPeer:
|
||||
Log.d("requestPairing", "Pairing already started by the other end, accepting their request.");
|
||||
acceptPairing();
|
||||
return;
|
||||
case NotPaired:
|
||||
;
|
||||
}
|
||||
@@ -240,73 +244,47 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
return;
|
||||
}
|
||||
|
||||
SendPackageStatusCallback callback = new SendPackageStatusCallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
if (pairingTimer != null) pairingTimer.cancel();
|
||||
pairingTimer = new Timer();
|
||||
pairingTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (PairingCallback cb : pairingCallback) {
|
||||
cb.pairingFailed(context.getString(R.string.error_timed_out));
|
||||
}
|
||||
Log.e("KDE/Device","Unpairing (timeout A)");
|
||||
pairStatus = PairStatus.NotPaired;
|
||||
}
|
||||
}, 30*1000); //Time to wait for the other to accept
|
||||
pairStatus = PairStatus.Requested;
|
||||
for (BasePairingHandler ph : pairingHandlers.values()) {
|
||||
ph.requestPairing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable e) {
|
||||
for (PairingCallback cb : pairingCallback) {
|
||||
cb.pairingFailed(context.getString(R.string.error_could_not_send_package));
|
||||
}
|
||||
Log.e("KDE/Device","Unpairing (sendFailed A)");
|
||||
pairStatus = PairStatus.NotPaired;
|
||||
}
|
||||
};
|
||||
|
||||
ArrayList<BaseLink> mLinks = new ArrayList<BaseLink>(links);
|
||||
for (final BaseLink link : mLinks) {
|
||||
link.getLinkProvider().getPairingHandler().requestPairing(this,callback);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int getNotificationId() {
|
||||
return notificationId;
|
||||
}
|
||||
|
||||
public void unpair() {
|
||||
|
||||
//Log.e("Device","Unpairing (unpair)");
|
||||
for (BasePairingHandler ph : pairingHandlers.values()) {
|
||||
ph.unpair();
|
||||
}
|
||||
unpairInternal(); // Even if there are no pairing handlers, unpair
|
||||
}
|
||||
|
||||
/**
|
||||
* This method does not send an unpair package, instead it unpairs internally by deleting trusted device info. . Likely to be called after sending package from
|
||||
* pairing handler
|
||||
*/
|
||||
private void unpairInternal() {
|
||||
|
||||
//Log.e("Device","Unpairing (unpairInternal)");
|
||||
pairStatus = PairStatus.NotPaired;
|
||||
|
||||
SharedPreferences preferences = context.getSharedPreferences("trusted_devices", Context.MODE_PRIVATE);
|
||||
preferences.edit().remove(deviceId).apply();
|
||||
|
||||
// FIXME : We delete all device info here, but the xml file still persists
|
||||
SharedPreferences devicePreferences = context.getSharedPreferences(deviceId, Context.MODE_PRIVATE);
|
||||
devicePreferences.edit().clear().apply();
|
||||
|
||||
ArrayList<BaseLink> mLinks = new ArrayList<BaseLink>(links);
|
||||
for (final BaseLink link : mLinks) {
|
||||
link.getLinkProvider().getPairingHandler().unpair(this);
|
||||
}
|
||||
|
||||
for (PairingCallback cb : pairingCallback) cb.unpaired();
|
||||
|
||||
reloadPluginsFromSettings();
|
||||
|
||||
}
|
||||
|
||||
/* This method should be called after pairing is done from pairing handler. Calling this method again should not create any problem as most of the things will get over writter*/
|
||||
private void pairingDone() {
|
||||
|
||||
//Log.e("Device", "Storing as trusted, deviceId: "+deviceId);
|
||||
|
||||
if (pairingTimer != null) pairingTimer.cancel();
|
||||
|
||||
pairStatus = PairStatus.Paired;
|
||||
|
||||
//Store as trusted device
|
||||
@@ -318,11 +296,6 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
editor.putString("deviceType", deviceType.toString());
|
||||
editor.apply();
|
||||
|
||||
ArrayList<BaseLink> mLinks = new ArrayList<BaseLink>(links);
|
||||
for (final BaseLink link : mLinks) {
|
||||
link.getLinkProvider().getPairingHandler().pairingDone(this);
|
||||
}
|
||||
|
||||
reloadPluginsFromSettings();
|
||||
|
||||
for (PairingCallback cb : pairingCallback) {
|
||||
@@ -331,32 +304,18 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
|
||||
}
|
||||
|
||||
/* This method is called after accepting pair request form GUI */
|
||||
public void acceptPairing() {
|
||||
|
||||
Log.i("KDE/Device", "Accepted pair request started by the other device");
|
||||
|
||||
SendPackageStatusCallback callback = new SendPackageStatusCallback() {
|
||||
@Override
|
||||
protected void onSuccess() {
|
||||
pairingDone();
|
||||
}
|
||||
@Override
|
||||
protected void onFailure(Throwable e) {
|
||||
Log.e("Device","Unpairing (sendFailed B)");
|
||||
pairStatus = PairStatus.NotPaired;
|
||||
for (PairingCallback cb : pairingCallback) {
|
||||
cb.pairingFailed(context.getString(R.string.error_not_reachable));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ArrayList<BaseLink> mLinks = new ArrayList<BaseLink>(links);
|
||||
for (final BaseLink link : mLinks) {
|
||||
link.getLinkProvider().getPairingHandler().acceptPairing(this, callback);
|
||||
for (BasePairingHandler ph : pairingHandlers.values()) {
|
||||
ph.acceptPairing();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* This method is called after rejecting pairing from GUI */
|
||||
public void rejectPairing() {
|
||||
|
||||
Log.i("KDE/Device", "Rejected pair request started by the other device");
|
||||
@@ -364,9 +323,8 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
//Log.e("Device","Unpairing (rejectPairing)");
|
||||
pairStatus = PairStatus.NotPaired;
|
||||
|
||||
ArrayList<BaseLink> mLinks = new ArrayList<BaseLink>(links);
|
||||
for (final BaseLink link : mLinks) {
|
||||
link.getLinkProvider().getPairingHandler().rejectPairing(this);
|
||||
for (BasePairingHandler ph : pairingHandlers.values()) {
|
||||
ph.rejectPairing();
|
||||
}
|
||||
|
||||
for (PairingCallback cb : pairingCallback) {
|
||||
@@ -375,7 +333,48 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Notification related methods used during pairing
|
||||
//
|
||||
public int getNotificationId() {
|
||||
return notificationId;
|
||||
}
|
||||
|
||||
public void displayPairingNotification() {
|
||||
|
||||
notificationId = (int)System.currentTimeMillis();
|
||||
|
||||
Intent intent = new Intent(getContext(), PairActivity.class);
|
||||
intent.putExtra("deviceId", getDeviceId());
|
||||
intent.putExtra("notificationId", notificationId);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(getContext(), 0, intent, PendingIntent.FLAG_ONE_SHOT);
|
||||
|
||||
Resources res = getContext().getResources();
|
||||
|
||||
Notification noti = new NotificationCompat.Builder(getContext())
|
||||
.setContentTitle(res.getString(R.string.pairing_request_from, getName()))
|
||||
.setContentText(res.getString(R.string.tap_to_answer))
|
||||
.setContentIntent(pendingIntent)
|
||||
.setTicker(res.getString(R.string.pair_requested))
|
||||
.setSmallIcon(android.R.drawable.ic_menu_help)
|
||||
.setAutoCancel(true)
|
||||
.setDefaults(Notification.DEFAULT_ALL)
|
||||
.build();
|
||||
|
||||
final NotificationManager notificationManager = (NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
try {
|
||||
notificationManager.notify(notificationId, noti);
|
||||
} catch(Exception e) {
|
||||
//4.1 will throw an exception about not having the VIBRATE permission, ignore it.
|
||||
//https://android.googlesource.com/platform/frameworks/base/+/android-4.2.1_r1.2%5E%5E!/
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelPairingNotification() {
|
||||
final NotificationManager notificationManager = (NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.cancel(notificationId);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
@@ -432,6 +431,36 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
|
||||
Log.i("KDE/Device","addLink "+link.getLinkProvider().getName()+" -> "+getName() + " active links: "+ links.size());
|
||||
|
||||
if (!pairingHandlers.containsKey(link.getName())) {
|
||||
BasePairingHandler.PairingHandlerCallback callback = new BasePairingHandler.PairingHandlerCallback() {
|
||||
@Override
|
||||
public void incomingRequest() {
|
||||
for (PairingCallback cb : pairingCallback) {
|
||||
cb.incomingRequest();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pairingDone() {
|
||||
Device.this.pairingDone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pairingFailed(String error) {
|
||||
for (PairingCallback cb : pairingCallback) {
|
||||
cb.pairingFailed(error);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unpaired() {
|
||||
unpairInternal();
|
||||
}
|
||||
};
|
||||
pairingHandlers.put(link.getName(), link.getPairingHandler(this, callback));
|
||||
}
|
||||
pairingHandlers.get(link.getName()).setLink(link);
|
||||
|
||||
/*
|
||||
Collections.sort(links, new Comparator<BaseLink>() {
|
||||
@Override
|
||||
@@ -451,6 +480,18 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
public void removeLink(BaseLink link) {
|
||||
//FilesHelper.LogOpenFileCount();
|
||||
|
||||
/* Remove pairing handler corresponding to that link too if it was the only link*/
|
||||
boolean linkPresent = false;
|
||||
for (BaseLink bl : links) {
|
||||
if (bl.getName().equals(link.getName())) {
|
||||
linkPresent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!linkPresent) {
|
||||
pairingHandlers.remove(link.getName());
|
||||
}
|
||||
|
||||
link.removePackageReceiver(this);
|
||||
links.remove(link);
|
||||
Log.i("KDE/Device", "removeLink: " + link.getLinkProvider().getName() + " -> " + getName() + " active links: " + links.size());
|
||||
@@ -465,113 +506,15 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
if (np.getType().equals(NetworkPackage.PACKAGE_TYPE_PAIR)) {
|
||||
|
||||
Log.i("KDE/Device", "Pair package");
|
||||
|
||||
boolean wantsPair = np.getBoolean("pair");
|
||||
|
||||
if (wantsPair == isPaired()) {
|
||||
if (pairStatus == PairStatus.Requested) {
|
||||
//Log.e("Device","Unpairing (pair rejected)");
|
||||
pairStatus = PairStatus.NotPaired;
|
||||
if (pairingTimer != null) pairingTimer.cancel();
|
||||
for (PairingCallback cb : pairingCallback) {
|
||||
cb.pairingFailed(context.getString(R.string.error_canceled_by_other_peer));
|
||||
}
|
||||
} else if (pairStatus == PairStatus.Paired) {
|
||||
// If I consider the device be paired, but still it is sending a pair request send my pairing package
|
||||
ArrayList<BaseLink> mLinks = new ArrayList<BaseLink>(links);
|
||||
for (final BaseLink link : mLinks) {
|
||||
// Send required link attributes for link
|
||||
link.getLinkProvider().getPairingHandler().acceptPairing(this, null);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (wantsPair) {
|
||||
|
||||
//Retrieve their public key
|
||||
ArrayList<BaseLink> mLinks = new ArrayList<BaseLink>(links);
|
||||
for (final BaseLink link : mLinks) {
|
||||
Log.e("KDE/Device", "Pairing Handler Count " + pairingHandlers.size());
|
||||
for (BasePairingHandler ph: pairingHandlers.values()) {
|
||||
try {
|
||||
link.getLinkProvider().getPairingHandler().packageReceived(this, np);
|
||||
ph.packageReceived(np);
|
||||
} catch (Exception e) {
|
||||
for (Device.PairingCallback cb : pairingCallback) {
|
||||
cb.pairingFailed(context.getString(R.string.error_invalid_key));
|
||||
}
|
||||
// There should be no exception here
|
||||
}
|
||||
}
|
||||
|
||||
if (pairStatus == PairStatus.Requested) { //We started pairing
|
||||
|
||||
Log.i("KDE/Pairing","Pair answer");
|
||||
|
||||
if (pairingTimer != null) pairingTimer.cancel();
|
||||
|
||||
pairingDone();
|
||||
|
||||
} else {
|
||||
|
||||
Log.i("KDE/Pairing","Pair request");
|
||||
|
||||
Intent intent = new Intent(context, PairActivity.class);
|
||||
intent.putExtra("deviceId", deviceId);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT);
|
||||
|
||||
Resources res = context.getResources();
|
||||
|
||||
Notification noti = new NotificationCompat.Builder(context)
|
||||
.setContentTitle(res.getString(R.string.pairing_request_from, getName()))
|
||||
.setContentText(res.getString(R.string.tap_to_answer))
|
||||
.setContentIntent(pendingIntent)
|
||||
.setTicker(res.getString(R.string.pair_requested))
|
||||
.setSmallIcon(android.R.drawable.ic_menu_help)
|
||||
.setAutoCancel(true)
|
||||
.setDefaults(Notification.DEFAULT_ALL)
|
||||
.build();
|
||||
|
||||
|
||||
final NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationId = (int)System.currentTimeMillis();
|
||||
try {
|
||||
notificationManager.notify(notificationId, noti);
|
||||
} catch(Exception e) {
|
||||
//4.1 will throw an exception about not having the VIBRATE permission, ignore it.
|
||||
//https://android.googlesource.com/platform/frameworks/base/+/android-4.2.1_r1.2%5E%5E!/
|
||||
}
|
||||
|
||||
if (pairingTimer != null) pairingTimer.cancel();
|
||||
pairingTimer = new Timer();
|
||||
|
||||
pairingTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.e("KDE/Device","Unpairing (timeout B)");
|
||||
pairStatus = PairStatus.NotPaired;
|
||||
notificationManager.cancel(notificationId);
|
||||
}
|
||||
}, 25*1000); //Time to show notification, waiting for user to accept (peer will timeout in 30 seconds)
|
||||
pairStatus = PairStatus.RequestedByPeer;
|
||||
for (PairingCallback cb : pairingCallback) cb.incomingRequest();
|
||||
|
||||
}
|
||||
} else {
|
||||
Log.i("KDE/Pairing","Unpair request");
|
||||
|
||||
if (pairStatus == PairStatus.Requested) {
|
||||
pairingTimer.cancel();
|
||||
for (PairingCallback cb : pairingCallback) {
|
||||
cb.pairingFailed(context.getString(R.string.error_canceled_by_other_peer));
|
||||
}
|
||||
} else if (pairStatus == PairStatus.Paired) {
|
||||
SharedPreferences preferences = context.getSharedPreferences("trusted_devices", Context.MODE_PRIVATE);
|
||||
preferences.edit().remove(deviceId).apply();
|
||||
reloadPluginsFromSettings();
|
||||
}
|
||||
|
||||
pairStatus = PairStatus.NotPaired;
|
||||
for (PairingCallback cb : pairingCallback) cb.unpaired();
|
||||
|
||||
}
|
||||
} else if (isPaired()) {
|
||||
|
||||
for (Plugin plugin : plugins.values()) {
|
||||
@@ -588,9 +531,11 @@ public class Device implements BaseLink.PackageReceiver {
|
||||
|
||||
Log.e("KDE/onPackageReceived","Device not paired, ignoring package!");
|
||||
|
||||
if (pairStatus != PairStatus.Requested) {
|
||||
// If it is pair package, it should be captured by "if" at start
|
||||
// If not and device is paired, it should be captured by isPaired
|
||||
// Else unpair, this handles the situation when one device unpairs, but other dont know like unpairing when wi-fi is off
|
||||
|
||||
unpair();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user