File indexing completed on 2024-12-22 04:41:38

0001 /*
0002  * SPDX-FileCopyrightText: 2014 Albert Vaca Cintora <albertvaka@gmail.com>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 package org.kde.kdeconnect.Plugins.ClibpoardPlugin;
0008 
0009 
0010 import android.Manifest;
0011 import android.app.Activity;
0012 import android.content.ClipData;
0013 import android.content.ClipboardManager;
0014 import android.content.Context;
0015 import android.content.pm.PackageManager;
0016 import android.os.Build;
0017 import android.widget.Toast;
0018 
0019 import androidx.annotation.DrawableRes;
0020 import androidx.annotation.NonNull;
0021 import androidx.core.content.ContextCompat;
0022 
0023 import org.kde.kdeconnect.NetworkPacket;
0024 import org.kde.kdeconnect.Plugins.Plugin;
0025 import org.kde.kdeconnect.Plugins.PluginFactory;
0026 import org.kde.kdeconnect_tp.R;
0027 
0028 @PluginFactory.LoadablePlugin
0029 public class ClipboardPlugin extends Plugin {
0030 
0031     /**
0032      * Packet containing just clipboard contents, sent when a device updates its clipboard.
0033      * <p>
0034      * The body should look like so:
0035      * {
0036      * "content": "password"
0037      * }
0038      */
0039     private final static String PACKET_TYPE_CLIPBOARD = "kdeconnect.clipboard";
0040 
0041     /**
0042      * Packet containing clipboard contents and a timestamp that the contents were last updated, sent
0043      * on first connection
0044      * <p>
0045      * The timestamp is milliseconds since epoch. It can be 0, which indicates that the clipboard
0046      * update time is currently unknown.
0047      * <p>
0048      * The body should look like so:
0049      * {
0050      * "timestamp": 542904563213,
0051      * "content": "password"
0052      * }
0053      */
0054     private final static String PACKET_TYPE_CLIPBOARD_CONNECT = "kdeconnect.clipboard.connect";
0055 
0056     @Override
0057     public @NonNull String getDisplayName() {
0058         return context.getResources().getString(R.string.pref_plugin_clipboard);
0059     }
0060 
0061     @Override
0062     public @NonNull String getDescription() {
0063         return context.getResources().getString(R.string.pref_plugin_clipboard_desc);
0064     }
0065 
0066     @Override
0067     public boolean onPacketReceived(@NonNull NetworkPacket np) {
0068         String content = np.getString("content");
0069         switch (np.getType()) {
0070             case (PACKET_TYPE_CLIPBOARD):
0071                 ClipboardListener.instance(context).setText(content);
0072                 return true;
0073             case(PACKET_TYPE_CLIPBOARD_CONNECT):
0074                 long packetTime = np.getLong("timestamp");
0075                 // If the packetTime is 0, it means the timestamp is unknown (so do nothing).
0076                 if (packetTime == 0 || packetTime < ClipboardListener.instance(context).getUpdateTimestamp()) {
0077                     return false;
0078                 }
0079 
0080                 ClipboardListener.instance(context).setText(content);
0081                 return true;
0082         }
0083         throw new UnsupportedOperationException("Unknown packet type: " + np.getType());
0084     }
0085 
0086     private final ClipboardListener.ClipboardObserver observer = this::propagateClipboard;
0087 
0088     void propagateClipboard(String content) {
0089         NetworkPacket np = new NetworkPacket(ClipboardPlugin.PACKET_TYPE_CLIPBOARD);
0090         np.set("content", content);
0091         device.sendPacket(np);
0092     }
0093 
0094     private void sendConnectPacket() {
0095         String content = ClipboardListener.instance(context).getCurrentContent();
0096         NetworkPacket np = new NetworkPacket(ClipboardPlugin.PACKET_TYPE_CLIPBOARD_CONNECT);
0097         long timestamp = ClipboardListener.instance(context).getUpdateTimestamp();
0098         np.set("timestamp", timestamp);
0099         np.set("content", content);
0100         device.sendPacket(np);
0101     }
0102 
0103 
0104     @Override
0105     public boolean onCreate() {
0106         ClipboardListener.instance(context).registerObserver(observer);
0107         sendConnectPacket();
0108         return true;
0109     }
0110 
0111     @Override
0112     public void onDestroy() {
0113         ClipboardListener.instance(context).removeObserver(observer);
0114     }
0115 
0116     @Override
0117     public @NonNull String[] getSupportedPacketTypes() {
0118         return new String[]{PACKET_TYPE_CLIPBOARD, PACKET_TYPE_CLIPBOARD_CONNECT};
0119     }
0120 
0121     @Override
0122     public @NonNull String[] getOutgoingPacketTypes() {
0123         return new String[]{PACKET_TYPE_CLIPBOARD, PACKET_TYPE_CLIPBOARD_CONNECT};
0124     }
0125 
0126     @Override
0127     public @NonNull String getActionName() {
0128         return context.getString(R.string.send_clipboard);
0129     }
0130 
0131     @Override
0132     public boolean displayAsButton(Context context) {
0133         return Build.VERSION.SDK_INT > Build.VERSION_CODES.P &&
0134                 ContextCompat.checkSelfPermission(context, Manifest.permission.READ_LOGS) == PackageManager.PERMISSION_DENIED;
0135     }
0136 
0137     @Override
0138     public @DrawableRes int getIcon() {
0139         return R.drawable.ic_baseline_content_paste_24;
0140     }
0141 
0142     @Override
0143     public void startMainActivity(Activity activity) {
0144         if (device != null) {
0145             ClipboardManager clipboardManager = ContextCompat.getSystemService(this.context,
0146                     ClipboardManager.class);
0147             ClipData.Item item;
0148             if (clipboardManager.hasPrimaryClip()) {
0149                 item = clipboardManager.getPrimaryClip().getItemAt(0);
0150                 String content = item.coerceToText(this.context).toString();
0151                 this.propagateClipboard(content);
0152                 Toast.makeText(this.context, R.string.pref_plugin_clipboard_sent, Toast.LENGTH_SHORT).show();
0153             }
0154         }
0155     }
0156 
0157 }