From 34c80314ed9c5199b45d570fe6f2b341b214aa1f Mon Sep 17 00:00:00 2001 From: Anjani Kumar Date: Sat, 18 Apr 2020 03:09:30 +0530 Subject: [PATCH] This reverts commit 0fc5d0907827451092afed17fb04dc1b3417e316. --- AndroidManifest.xml | 5 + res/values/strings.xml | 2 + res/values/styles.xml | 8 ++ src/org/kde/kdeconnect/BackgroundService.java | 23 +++-- .../ClipboardFloatingActivity.java | 93 +++++++++++++++++++ .../ClibpoardPlugin/ClipboardPlugin.java | 25 +---- .../UserInterface/MainActivity.java | 6 -- .../NoticeAlertDialogFragment.java | 68 -------------- 8 files changed, 126 insertions(+), 104 deletions(-) create mode 100644 src/org/kde/kdeconnect/Plugins/ClibpoardPlugin/ClipboardFloatingActivity.java delete mode 100644 src/org/kde/kdeconnect/UserInterface/NoticeAlertDialogFragment.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index eb8221f7..6416c0ca 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -135,6 +135,11 @@ + + KDE Connect Not connected to any device Connected to: %s + Send Clipboard Telephony notifier Send notifications for incoming calls Battery report @@ -17,6 +18,7 @@ Allows to browse this device\'s filesystem remotely Clipboard sync Share the clipboard content + Clipboard Sent Remote input Use your phone or tablet as a touchpad and keyboard Slideshow remote diff --git a/res/values/styles.xml b/res/values/styles.xml index 7faa68e4..b5585697 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -49,4 +49,12 @@ + diff --git a/src/org/kde/kdeconnect/BackgroundService.java b/src/org/kde/kdeconnect/BackgroundService.java index e878ff2c..8fe6b791 100644 --- a/src/org/kde/kdeconnect/BackgroundService.java +++ b/src/org/kde/kdeconnect/BackgroundService.java @@ -44,6 +44,7 @@ import org.kde.kdeconnect.Backends.LanBackend.LanLinkProvider; import org.kde.kdeconnect.Helpers.NotificationHelper; import org.kde.kdeconnect.Helpers.SecurityHelpers.RsaHelper; import org.kde.kdeconnect.Helpers.SecurityHelpers.SslHelper; +import org.kde.kdeconnect.Plugins.ClibpoardPlugin.ClipboardFloatingActivity; import org.kde.kdeconnect.Plugins.Plugin; import org.kde.kdeconnect.Plugins.PluginFactory; import org.kde.kdeconnect.Plugins.RunCommandPlugin.RunCommandActivity; @@ -346,10 +347,10 @@ public class BackgroundService extends Service { } ArrayList connectedDevices = new ArrayList<>(); - ArrayList deviceIds = new ArrayList<>(); + ArrayList connectedDeviceIds = new ArrayList<>(); for (Device device : getDevices().values()) { if (device.isReachable() && device.isPaired()) { - deviceIds.add(device.getDeviceId()); + connectedDeviceIds.add(device.getDeviceId()); connectedDevices.add(device.getName()); } } @@ -358,20 +359,30 @@ public class BackgroundService extends Service { notification.setContentText(getString(R.string.foreground_notification_no_devices)); } else { notification.setContentText(getString(R.string.foreground_notification_devices, TextUtils.join(", ", connectedDevices))); - if (deviceIds.size() == 1) { + + // Adding an action button to send clipboard manually in Android 10 and later. + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { + Intent sendClipboard = new Intent(this, ClipboardFloatingActivity.class); + sendClipboard.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); + sendClipboard.putExtra("connectedDeviceIds", connectedDeviceIds); + PendingIntent sendPendingClipboard = PendingIntent.getActivity(this, 3, sendClipboard, PendingIntent.FLAG_UPDATE_CURRENT); + notification.addAction(0, getString(R.string.foreground_notification_send_clipboard), sendPendingClipboard); + } + + if (connectedDeviceIds.size() == 1) { // Adding two action buttons only when there is a single device connected. // Setting up Send File Intent. Intent sendFile = new Intent(this, SendFileActivity.class); - sendFile.putExtra("deviceId", deviceIds.get(0)); + sendFile.putExtra("deviceId", connectedDeviceIds.get(0)); PendingIntent sendPendingFile = PendingIntent.getActivity(this, 1, sendFile, PendingIntent.FLAG_UPDATE_CURRENT); notification.addAction(0, getString(R.string.send_files), sendPendingFile); // Checking if there are registered commands and adding the button. - Device device = getDevice(deviceIds.get(0)); + Device device = getDevice(connectedDeviceIds.get(0)); RunCommandPlugin plugin = (RunCommandPlugin) device.getPlugin("RunCommandPlugin"); if (plugin != null && !plugin.getCommandList().isEmpty()) { Intent runCommand = new Intent(this, RunCommandActivity.class); - runCommand.putExtra("deviceId", deviceIds.get(0)); + runCommand.putExtra("deviceId", connectedDeviceIds.get(0)); PendingIntent runPendingCommand = PendingIntent.getActivity(this, 2, runCommand, PendingIntent.FLAG_UPDATE_CURRENT); notification.addAction(0, getString(R.string.pref_plugin_runcommand), runPendingCommand); } diff --git a/src/org/kde/kdeconnect/Plugins/ClibpoardPlugin/ClipboardFloatingActivity.java b/src/org/kde/kdeconnect/Plugins/ClibpoardPlugin/ClipboardFloatingActivity.java new file mode 100644 index 00000000..57e7abcf --- /dev/null +++ b/src/org/kde/kdeconnect/Plugins/ClibpoardPlugin/ClipboardFloatingActivity.java @@ -0,0 +1,93 @@ +/* + * Copyright 2020 Anjani Kumar + * + * 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 . + */ + +package org.kde.kdeconnect.Plugins.ClibpoardPlugin; + +import androidx.appcompat.app.AppCompatActivity; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.os.Bundle; +import android.view.WindowManager; +import android.widget.Toast; + +import org.kde.kdeconnect.BackgroundService; +import org.kde.kdeconnect.Device; +import org.kde.kdeconnect_tp.R; + +import java.util.ArrayList; + +/* + An activity to access the clipboard on Android 10 and later by raising over other apps. + This is invisible and doesn't require any interaction from the user. + This should be called when a change in clipboard is detected. This can be done by manually + when user wants to send the clipboard or by reading system log files which requires a special + privileged permission android.permission.READ_LOGS. + https://developer.android.com/reference/android/Manifest.permission#READ_LOGS + This permission can be gained by only from the adb by the user. + https://www.reddit.com/r/AndroidBusters/comments/fh60lt/how_to_solve_a_problem_with_the_clipboard_on/ + + Currently this activity is bering triggered from a button in Foreground Notification. +* */ +public class ClipboardFloatingActivity extends AppCompatActivity { + + private ArrayList connectedDevices = new ArrayList<>(); + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + if (hasFocus) { + // We are now sure that clipboard can be accessed from here. + ClipboardManager clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); + ClipData.Item item; + if (clipboardManager.hasPrimaryClip()) { + item = clipboardManager.getPrimaryClip().getItemAt(0); + String content = item.coerceToText(this).toString(); + for (Device device : connectedDevices) { + ClipboardPlugin clipboardPlugin = (ClipboardPlugin) device.getPlugin("ClipboardPlugin"); + if (clipboardPlugin != null) { + clipboardPlugin.propagateClipboard(content); + } + } + Toast.makeText(this, R.string.pref_plugin_clipboard_sent, Toast.LENGTH_SHORT).show(); + } + finish(); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + WindowManager.LayoutParams wlp = getWindow().getAttributes(); + wlp.dimAmount = 0; + wlp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS | + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; + + getWindow().setAttributes(wlp); + ArrayList connectedDeviceIds = getIntent().getStringArrayListExtra("connectedDeviceIds"); + if (connectedDeviceIds != null) { + for (String deviceId : connectedDeviceIds) { + connectedDevices.add(BackgroundService.getInstance().getDevice(deviceId)); + } + } + } +} + diff --git a/src/org/kde/kdeconnect/Plugins/ClibpoardPlugin/ClipboardPlugin.java b/src/org/kde/kdeconnect/Plugins/ClibpoardPlugin/ClipboardPlugin.java index a0de5e03..54cae9ef 100644 --- a/src/org/kde/kdeconnect/Plugins/ClibpoardPlugin/ClipboardPlugin.java +++ b/src/org/kde/kdeconnect/Plugins/ClibpoardPlugin/ClipboardPlugin.java @@ -20,15 +20,11 @@ package org.kde.kdeconnect.Plugins.ClibpoardPlugin; -import android.os.Build; -import androidx.fragment.app.DialogFragment; -import androidx.preference.PreferenceManager; import org.kde.kdeconnect.NetworkPacket; import org.kde.kdeconnect.Plugins.Plugin; import org.kde.kdeconnect.Plugins.PluginFactory; -import org.kde.kdeconnect.UserInterface.NoticeAlertDialogFragment; import org.kde.kdeconnect_tp.R; @PluginFactory.LoadablePlugin @@ -59,8 +55,6 @@ public class ClipboardPlugin extends Plugin { */ private final static String PACKET_TYPE_CLIPBOARD_CONNECT = "kdeconnect.clipboard.connect"; - private final static String ANDROID_10_INCOMPAT_DIALOG_SHOWN_PREFERENCE = "android10IncompatDialogShown"; - @Override public String getDisplayName() { return context.getResources().getString(R.string.pref_plugin_clipboard); @@ -93,7 +87,7 @@ public class ClipboardPlugin extends Plugin { private final ClipboardListener.ClipboardObserver observer = this::propagateClipboard; - private void propagateClipboard(String content) { + void propagateClipboard(String content) { NetworkPacket np = new NetworkPacket(ClipboardPlugin.PACKET_TYPE_CLIPBOARD); np.set("content", content); device.sendPacket(np); @@ -108,26 +102,9 @@ public class ClipboardPlugin extends Plugin { device.sendPacket(np); } - @Override - public boolean checkRequiredPermissions() { - return Build.VERSION.SDK_INT <= Build.VERSION_CODES.P || PreferenceManager.getDefaultSharedPreferences(context).getBoolean(ANDROID_10_INCOMPAT_DIALOG_SHOWN_PREFERENCE, false); - } - - @Override - public DialogFragment getPermissionExplanationDialog() { - PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(ANDROID_10_INCOMPAT_DIALOG_SHOWN_PREFERENCE, true).apply(); - return new NoticeAlertDialogFragment.Builder() - .setTitle(R.string.pref_plugin_clipboard) - .setMessage(R.string.clipboard_android_x_incompat) - .setPositiveButton(R.string.sad_ok) - .create(); - } @Override public boolean onCreate() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - return false; - } ClipboardListener.instance(context).registerObserver(observer); sendConnectPacket(); return true; diff --git a/src/org/kde/kdeconnect/UserInterface/MainActivity.java b/src/org/kde/kdeconnect/UserInterface/MainActivity.java index ee862e08..55d3566f 100644 --- a/src/org/kde/kdeconnect/UserInterface/MainActivity.java +++ b/src/org/kde/kdeconnect/UserInterface/MainActivity.java @@ -378,12 +378,6 @@ public class MainActivity extends AppCompatActivity implements SharedPreferences } } - public void reloadCurrentDevicePlugins() { - BackgroundService.RunCommand(this, service -> { - Device device = service.getDevice(mCurrentDevice); - device.reloadPluginsFromSettings(); - }); - } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { diff --git a/src/org/kde/kdeconnect/UserInterface/NoticeAlertDialogFragment.java b/src/org/kde/kdeconnect/UserInterface/NoticeAlertDialogFragment.java deleted file mode 100644 index b0c40b6a..00000000 --- a/src/org/kde/kdeconnect/UserInterface/NoticeAlertDialogFragment.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2019 Erik Duisters - * - * 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 . - */ - -package org.kde.kdeconnect.UserInterface; - -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.pm.PackageManager; -import android.os.Bundle; - -import androidx.annotation.Nullable; -import androidx.preference.PreferenceManager; - -import org.kde.kdeconnect_tp.R; - -public class NoticeAlertDialogFragment extends AlertDialogFragment { - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setCallback(new Callback() { - @Override - public void onPositiveButtonClicked() { - //TODO: Find a way to pass this callback from the Builder. For now, this is only used in one place and this is the callback needed. - MainActivity mainActivity = (MainActivity)requireActivity(); - mainActivity.reloadCurrentDevicePlugins(); - } - }); - } - - public static class Builder extends AbstractBuilder { - - public Builder() { - super(); - setTitle(R.string.pref_plugin_clipboard); - setMessage(R.string.clipboard_android_x_incompat); - setPositiveButton(R.string.sad_ok); - } - - @Override - public Builder getThis() { - return this; - } - - @Override - protected NoticeAlertDialogFragment createFragment() { - return new NoticeAlertDialogFragment(); - } - } -}