Commit 5dc65ee9 authored by Colin Redman's avatar Colin Redman Committed by Albert Vaca Cintora

Clipboard sync on new connections

Summary: Timestamp on changes to clipboards so that when a new device connects it can sync both clipboards to the most recent updated clipboard.

Reviewers: #kde_connect, albertvaka

Reviewed By: #kde_connect, albertvaka

Subscribers: albertvaka, sredman, kdeconnect

Tags: #kde_connect

Differential Revision: https://phabricator.kde.org/D22585
parent 4be5800b
......@@ -41,6 +41,7 @@ public class ClipboardListener {
private final Context context;
private String currentContent;
private long updateTimestamp;
private ClipboardManager cm = null;
private ClipboardManager.OnPrimaryClipChangedListener listener;
......@@ -76,7 +77,7 @@ public class ClipboardListener {
if (content.equals(currentContent)) {
return;
}
updateTimestamp = System.currentTimeMillis();
currentContent = content;
for (ClipboardObserver observer : observers) {
......@@ -91,8 +92,17 @@ public class ClipboardListener {
});
}
public String getCurrentContent() {
return currentContent;
}
public long getUpdateTimestamp() {
return updateTimestamp;
}
@SuppressWarnings("deprecation")
public void setText(String text) {
updateTimestamp = System.currentTimeMillis();
currentContent = text;
cm.setText(text);
}
......
......@@ -28,8 +28,31 @@ import org.kde.kdeconnect_tp.R;
@PluginFactory.LoadablePlugin
public class ClipboardPlugin extends Plugin {
/**
* Packet containing just clipboard contents, sent when a device updates its clipboard.
* <p>
* The body should look like so:
* {
* "content": "password"
* }
*/
private final static String PACKET_TYPE_CLIPBOARD = "kdeconnect.clipboard";
/**
* Packet containing clipboard contents and a timestamp that the contents were last updated, sent
* on first connection
* <p>
* The timestamp is milliseconds since epoch. It can be 0, which indicates that the clipboard
* update time is currently unknown.
* <p>
* The body should look like so:
* {
* "timestamp": 542904563213,
* "content": "password"
* }
*/
private final static String PACKET_TYPE_CLIPBOARD_CONNECT = "kdeconnect.clipboard.connect";
@Override
public String getDisplayName() {
return context.getResources().getString(R.string.pref_plugin_clipboard);
......@@ -43,19 +66,44 @@ public class ClipboardPlugin extends Plugin {
@Override
public boolean onPacketReceived(NetworkPacket np) {
String content = np.getString("content");
switch (np.getType()) {
case (PACKET_TYPE_CLIPBOARD):
ClipboardListener.instance(context).setText(content);
return true;
case(PACKET_TYPE_CLIPBOARD_CONNECT):
long packetTime = np.getLong("timestamp");
// If the packetTime is 0, it means the timestamp is unknown (so do nothing).
if (packetTime == 0 || packetTime < ClipboardListener.instance(context).getUpdateTimestamp()) {
return false;
}
ClipboardListener.instance(context).setText(content);
return true;
}
throw new UnsupportedOperationException("Unknown packet type: " + np.getType());
}
private final ClipboardListener.ClipboardObserver observer = content -> {
private final ClipboardListener.ClipboardObserver observer = this::propagateClipboard;
private void propagateClipboard(String content) {
NetworkPacket np = new NetworkPacket(ClipboardPlugin.PACKET_TYPE_CLIPBOARD);
np.set("content", content);
device.sendPacket(np);
};
}
private void sendConnectPacket() {
String content = ClipboardListener.instance(context).getCurrentContent();
NetworkPacket np = new NetworkPacket(ClipboardPlugin.PACKET_TYPE_CLIPBOARD_CONNECT);
long timestamp = ClipboardListener.instance(context).getUpdateTimestamp();
np.set("timestamp", timestamp);
np.set("content", content);
device.sendPacket(np);
}
@Override
public boolean onCreate() {
ClipboardListener.instance(context).registerObserver(observer);
sendConnectPacket();
return true;
}
......@@ -66,12 +114,12 @@ public class ClipboardPlugin extends Plugin {
@Override
public String[] getSupportedPacketTypes() {
return new String[]{PACKET_TYPE_CLIPBOARD};
return new String[]{PACKET_TYPE_CLIPBOARD, PACKET_TYPE_CLIPBOARD_CONNECT};
}
@Override
public String[] getOutgoingPacketTypes() {
return new String[]{PACKET_TYPE_CLIPBOARD};
return new String[]{PACKET_TYPE_CLIPBOARD, PACKET_TYPE_CLIPBOARD_CONNECT};
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment