fix: Android, try sync clipboard on connecting (#10218)
* fix: Android, try sync clipboard on connecting Signed-off-by: fufesou <linlong1266@gmail.com> * Android, clipboard, more clear skip check Signed-off-by: fufesou <linlong1266@gmail.com> * comments Signed-off-by: fufesou <linlong1266@gmail.com> * comment todo: Android clipboard listener, callback twice Signed-off-by: fufesou <linlong1266@gmail.com> * Android, clipboard, remove listner Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
parent
8f44787ba3
commit
3c838e7a92
@ -306,7 +306,7 @@ class FloatingWindowService : Service(), View.OnTouchListener {
|
||||
popupMenu.menu.add(0, idShowRustDesk, 0, translate("Show RustDesk"))
|
||||
// For host side, clipboard sync
|
||||
val idSyncClipboard = 1
|
||||
val isClipboardListenerEnabled = MainActivity.rdClipboardManager?.isListening ?: false
|
||||
val isClipboardListenerEnabled = MainActivity.rdClipboardManager?.isCaptureStarted ?: false
|
||||
if (isClipboardListenerEnabled) {
|
||||
popupMenu.menu.add(0, idSyncClipboard, 0, translate("Update client clipboard"))
|
||||
}
|
||||
|
@ -103,7 +103,6 @@ class MainActivity : FlutterActivity() {
|
||||
mainService?.let {
|
||||
unbindService(serviceConnection)
|
||||
}
|
||||
rdClipboardManager?.rustEnableServiceClipboard(false)
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
@ -221,6 +220,10 @@ class MainActivity : FlutterActivity() {
|
||||
result.success(true)
|
||||
|
||||
}
|
||||
"try_sync_clipboard" -> {
|
||||
rdClipboardManager?.syncClipboard(true)
|
||||
result.success(true)
|
||||
}
|
||||
GET_START_ON_BOOT_OPT -> {
|
||||
val prefs = getSharedPreferences(KEY_SHARED_PREFERENCES, MODE_PRIVATE)
|
||||
result.success(prefs.getBoolean(KEY_START_ON_BOOT_OPT, false))
|
||||
@ -402,13 +405,4 @@ class MainActivity : FlutterActivity() {
|
||||
super.onStart()
|
||||
stopService(Intent(this, FloatingWindowService::class.java))
|
||||
}
|
||||
|
||||
// For client side
|
||||
// When swithing from other app to this app, try to sync clipboard.
|
||||
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||
super.onWindowFocusChanged(hasFocus)
|
||||
if (hasFocus) {
|
||||
rdClipboardManager?.syncClipboard(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -433,6 +433,7 @@ class MainService : Service() {
|
||||
checkMediaPermission()
|
||||
_isStart = true
|
||||
FFI.setFrameRawEnable("video",true)
|
||||
MainActivity.rdClipboardManager?.setCaptureStarted(_isStart)
|
||||
return true
|
||||
}
|
||||
|
||||
@ -441,6 +442,7 @@ class MainService : Service() {
|
||||
Log.d(logTag, "Stop Capture")
|
||||
FFI.setFrameRawEnable("video",false)
|
||||
_isStart = false
|
||||
MainActivity.rdClipboardManager?.setCaptureStarted(_isStart)
|
||||
// release video
|
||||
if (reuseVirtualDisplay) {
|
||||
// The virtual display video projection can be paused by calling `setSurface(null)`.
|
||||
|
@ -36,19 +36,19 @@ class RdClipboardManager(private val clipboardManager: ClipboardManager) {
|
||||
// though the `lastUpdatedClipData` will be set to null once.
|
||||
private var lastUpdatedClipData: ClipData? = null
|
||||
private var isClientEnabled = true;
|
||||
private var _isListening = false;
|
||||
val isListening: Boolean
|
||||
get() = _isListening
|
||||
private var _isCaptureStarted = false;
|
||||
|
||||
fun checkPrimaryClip(isClient: Boolean, isSync: Boolean) {
|
||||
val isCaptureStarted: Boolean
|
||||
get() = _isCaptureStarted
|
||||
|
||||
fun checkPrimaryClip(isClient: Boolean) {
|
||||
val clipData = clipboardManager.primaryClip
|
||||
if (clipData != null && clipData.itemCount > 0) {
|
||||
// Only handle the first item in the clipboard for now.
|
||||
val clip = clipData.getItemAt(0)
|
||||
val isHostSync = !isClient && isSync
|
||||
// Ignore the `isClipboardDataEqual()` check if it's a host sync operation.
|
||||
// Because it's a action manually triggered by the user.
|
||||
if (!isHostSync) {
|
||||
// Ignore the `isClipboardDataEqual()` check if it's a host operation.
|
||||
// Because it's an action manually triggered by the user.
|
||||
if (isClient) {
|
||||
if (lastUpdatedClipData != null && isClipboardDataEqual(clipData, lastUpdatedClipData!!)) {
|
||||
Log.d(logTag, "Clipboard data is the same as last update, ignore")
|
||||
return
|
||||
@ -95,13 +95,6 @@ class RdClipboardManager(private val clipboardManager: ClipboardManager) {
|
||||
}
|
||||
}
|
||||
|
||||
private val clipboardListener = object : ClipboardManager.OnPrimaryClipChangedListener {
|
||||
override fun onPrimaryClipChanged() {
|
||||
Log.d(logTag, "onPrimaryClipChanged")
|
||||
checkPrimaryClip(true, false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSupportedMimeType(mimeType: String): Boolean {
|
||||
return supportedMimeTypes.contains(mimeType)
|
||||
}
|
||||
@ -136,43 +129,23 @@ class RdClipboardManager(private val clipboardManager: ClipboardManager) {
|
||||
return true
|
||||
}
|
||||
|
||||
@Keep
|
||||
fun rustEnableServiceClipboard(enable: Boolean) {
|
||||
Log.d(logTag, "rustEnableServiceClipboard: enable: $enable, _isListening: $_isListening")
|
||||
if (enable) {
|
||||
if (!_isListening) {
|
||||
clipboardManager.addPrimaryClipChangedListener(clipboardListener)
|
||||
_isListening = true
|
||||
}
|
||||
} else {
|
||||
if (_isListening) {
|
||||
clipboardManager.removePrimaryClipChangedListener(clipboardListener)
|
||||
_isListening = false
|
||||
lastUpdatedClipData = null
|
||||
}
|
||||
}
|
||||
fun setCaptureStarted(started: Boolean) {
|
||||
_isCaptureStarted = started
|
||||
}
|
||||
|
||||
@Keep
|
||||
fun rustEnableClientClipboard(enable: Boolean) {
|
||||
Log.d(logTag, "rustEnableClientClipboard: enable: $enable")
|
||||
isClientEnabled = enable
|
||||
if (enable) {
|
||||
lastUpdatedClipData = clipboardManager.primaryClip
|
||||
} else {
|
||||
lastUpdatedClipData = null
|
||||
}
|
||||
lastUpdatedClipData = null
|
||||
}
|
||||
|
||||
fun syncClipboard(isClient: Boolean) {
|
||||
Log.d(logTag, "syncClipboard: isClient: $isClient, isClientEnabled: $isClientEnabled, _isListening: $_isListening")
|
||||
Log.d(logTag, "syncClipboard: isClient: $isClient, isClientEnabled: $isClientEnabled")
|
||||
if (isClient && !isClientEnabled) {
|
||||
return
|
||||
}
|
||||
if (!isClient && !_isListening) {
|
||||
return
|
||||
}
|
||||
checkPrimaryClip(isClient, true)
|
||||
checkPrimaryClip(isClient)
|
||||
}
|
||||
|
||||
@Keep
|
||||
|
@ -147,6 +147,19 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
|
||||
gFFI.chatModel.onVoiceCallClosed("End connetion");
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
if (state == AppLifecycleState.resumed) {
|
||||
trySyncClipboard();
|
||||
}
|
||||
}
|
||||
|
||||
// For client side
|
||||
// When swithing from other app to this app, try to sync clipboard.
|
||||
void trySyncClipboard() {
|
||||
gFFI.invokeMethod("try_sync_clipboard");
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeMetrics() {
|
||||
// If the soft keyboard is visible and the canvas has been changed(panned or scaled)
|
||||
|
@ -597,8 +597,6 @@ class _PermissionCheckerState extends State<PermissionChecker> {
|
||||
style: const TextStyle(color: MyTheme.darkGray),
|
||||
))
|
||||
]),
|
||||
PermissionRow(translate("Enable clipboard"), serverModel.clipboardOk,
|
||||
serverModel.toggleClipboard),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,6 @@ class ServerModel with ChangeNotifier {
|
||||
bool _inputOk = false;
|
||||
bool _audioOk = false;
|
||||
bool _fileOk = false;
|
||||
bool _clipboardOk = false;
|
||||
bool _showElevation = false;
|
||||
bool hideCm = false;
|
||||
int _connectStatus = 0; // Rendezvous Server status
|
||||
@ -60,8 +59,6 @@ class ServerModel with ChangeNotifier {
|
||||
|
||||
bool get fileOk => _fileOk;
|
||||
|
||||
bool get clipboardOk => _clipboardOk;
|
||||
|
||||
bool get showElevation => _showElevation;
|
||||
|
||||
int get connectStatus => _connectStatus;
|
||||
@ -212,10 +209,6 @@ class ServerModel with ChangeNotifier {
|
||||
_fileOk = fileOption != 'N';
|
||||
}
|
||||
|
||||
// clipboard
|
||||
final clipOption = await bind.mainGetOption(key: kOptionEnableClipboard);
|
||||
_clipboardOk = clipOption != 'N';
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@ -322,14 +315,6 @@ class ServerModel with ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
toggleClipboard() async {
|
||||
_clipboardOk = !_clipboardOk;
|
||||
bind.mainSetOption(
|
||||
key: kOptionEnableClipboard,
|
||||
value: _clipboardOk ? defaultOptionYes : 'N');
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
toggleInput() async {
|
||||
if (clients.isNotEmpty) {
|
||||
await showClientsMayNotBeChangedAlert(parent.target);
|
||||
|
@ -371,14 +371,6 @@ pub fn call_clipboard_manager_update_clipboard(data: &[u8]) -> JniResult<()> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call_clipboard_manager_enable_service_clipboard(enable: bool) -> JniResult<()> {
|
||||
_call_clipboard_manager(
|
||||
"rustEnableServiceClipboard",
|
||||
"(Z)V",
|
||||
&[JValue::Bool(jboolean::from(enable))],
|
||||
)
|
||||
}
|
||||
|
||||
pub fn call_clipboard_manager_enable_client_clipboard(enable: bool) -> JniResult<()> {
|
||||
_call_clipboard_manager(
|
||||
"rustEnableClientClipboard",
|
||||
|
@ -831,17 +831,6 @@ pub fn main_show_option(_key: String) -> SyncReturn<bool> {
|
||||
SyncReturn(false)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(target_os = "android")]
|
||||
fn enable_server_clipboard(keyboard_enabled: &str, clip_enabled: &str) {
|
||||
use scrap::android::ffi::call_clipboard_manager_enable_service_clipboard;
|
||||
let keyboard_enabled =
|
||||
config::option2bool(config::keys::OPTION_ENABLE_KEYBOARD, &keyboard_enabled);
|
||||
let clip_enabled = config::option2bool(config::keys::OPTION_ENABLE_CLIPBOARD, &clip_enabled);
|
||||
crate::ui_cm_interface::switch_permission_all("clipboard".to_owned(), clip_enabled);
|
||||
let _ = call_clipboard_manager_enable_service_clipboard(keyboard_enabled && clip_enabled);
|
||||
}
|
||||
|
||||
pub fn main_set_option(key: String, value: String) {
|
||||
#[cfg(target_os = "android")]
|
||||
if key.eq(config::keys::OPTION_ENABLE_KEYBOARD) {
|
||||
@ -849,11 +838,6 @@ pub fn main_set_option(key: String, value: String) {
|
||||
config::keys::OPTION_ENABLE_KEYBOARD,
|
||||
&value,
|
||||
));
|
||||
enable_server_clipboard(&value, &get_option(config::keys::OPTION_ENABLE_CLIPBOARD));
|
||||
}
|
||||
#[cfg(target_os = "android")]
|
||||
if key.eq(config::keys::OPTION_ENABLE_CLIPBOARD) {
|
||||
enable_server_clipboard(&get_option(config::keys::OPTION_ENABLE_KEYBOARD), &value);
|
||||
}
|
||||
if key.eq("custom-rendezvous-server") {
|
||||
set_option(key, value.clone());
|
||||
|
@ -8,8 +8,6 @@ use crate::ipc::{self, ClipboardFile, ClipboardNonFile, Data};
|
||||
use clipboard_master::{CallbackResult, ClipboardHandler};
|
||||
#[cfg(target_os = "android")]
|
||||
use hbb_common::config::{keys, option2bool};
|
||||
#[cfg(target_os = "android")]
|
||||
use scrap::android::ffi::call_clipboard_manager_enable_service_clipboard;
|
||||
use std::{
|
||||
io,
|
||||
sync::mpsc::{channel, RecvTimeoutError, Sender},
|
||||
@ -224,24 +222,13 @@ impl Handler {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
fn is_clipboard_enabled() -> bool {
|
||||
let keyboard_enabled = crate::ui_interface::get_option(keys::OPTION_ENABLE_KEYBOARD);
|
||||
let keyboard_enabled = option2bool(keys::OPTION_ENABLE_KEYBOARD, &keyboard_enabled);
|
||||
let clip_enabled = crate::ui_interface::get_option(keys::OPTION_ENABLE_CLIPBOARD);
|
||||
let clip_enabled = option2bool(keys::OPTION_ENABLE_CLIPBOARD, &clip_enabled);
|
||||
keyboard_enabled && clip_enabled
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
fn run(sp: EmptyExtraFieldService) -> ResultType<()> {
|
||||
let _res = call_clipboard_manager_enable_service_clipboard(is_clipboard_enabled());
|
||||
while sp.ok() {
|
||||
if let Some(msg) = crate::clipboard::get_clipboards_msg(false) {
|
||||
sp.send(msg);
|
||||
}
|
||||
std::thread::sleep(Duration::from_millis(INTERVAL));
|
||||
}
|
||||
let _res = call_clipboard_manager_enable_service_clipboard(false);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1372,8 +1372,14 @@ impl Connection {
|
||||
if !self.follow_remote_window {
|
||||
noperms.push(NAME_WINDOW_FOCUS);
|
||||
}
|
||||
if !self.clipboard_enabled()
|
||||
|| !self.peer_keyboard_enabled()
|
||||
// Do not consider the clipboard and keyboard permissions on Android.
|
||||
// Because syncing the clipboard on Android is manually triggered by the user in the floating ball.
|
||||
#[cfg(target_os = "android")]
|
||||
let keyboard_clip_noperm = self.disable_keyboard || self.disable_clipboard;
|
||||
#[cfg(not(target_os = "android"))]
|
||||
let keyboard_clip_noperm =
|
||||
!self.clipboard_enabled() || !self.peer_keyboard_enabled();
|
||||
if keyboard_clip_noperm
|
||||
|| crate::get_builtin_option(keys::OPTION_ONE_WAY_CLIPBOARD_REDIRECTION) == "Y"
|
||||
{
|
||||
noperms.push(super::clipboard_service::NAME);
|
||||
|
@ -312,17 +312,6 @@ pub fn switch_permission(id: i32, name: String, enabled: bool) {
|
||||
};
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(target_os = "android")]
|
||||
pub fn switch_permission_all(name: String, enabled: bool) {
|
||||
for (_, client) in CLIENTS.read().unwrap().iter() {
|
||||
allow_err!(client.tx.send(Data::SwitchPermission {
|
||||
name: name.clone(),
|
||||
enabled
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))]
|
||||
#[inline]
|
||||
pub fn get_clients_state() -> String {
|
||||
|
Loading…
x
Reference in New Issue
Block a user