From dc7dd4bcd1cd08df0efaea015d55d9e3099024c9 Mon Sep 17 00:00:00 2001 From: CaiFeng <2397707574@qq.com> Date: Mon, 29 Jan 2024 19:29:16 +0800 Subject: [PATCH] support copy paste interface --- README.md | 56 ++++++++++++++++++- .../cloudapp/ui/CasCloudPhoneActivity.java | 45 +++++++++++++-- .../api/CloudPhoneClipboardListener.java | 22 ++++++++ .../huawei/cloudphone/api/ICloudPhone.java | 13 +++++ .../cloudphone/apiimpl/CloudPhoneImeMgr.java | 39 +++++++++++-- .../cloudphone/apiimpl/CloudPhoneImpl.java | 15 +++++ 6 files changed, 176 insertions(+), 14 deletions(-) create mode 100644 cloudphone/src/main/java/com/huawei/cloudphone/api/CloudPhoneClipboardListener.java diff --git a/README.md b/README.md index abeee5b..deb85fe 100644 --- a/README.md +++ b/README.md @@ -409,7 +409,57 @@ implementation 'org.bouncycastle:bcprov-jdk15to18:1.71' cloudPhone.sendPermissionResult(requestCode, PackageManager.PERMISSION_GRANTED); ``` -#### 4.13 获取网络时延 +#### 4.13 注册剪切板变化监听 + +- 接口介绍 + + void registerClipboardListener(CloudPhoneClipboardListener listener); + +- 功能描述 + + 通过注册云手机剪切板监听回调,获取云手机剪切板内容。 + +- 参数介绍 + + ```java + @param { CloudPhoneClipboardListener } listener: 云手机剪切板监听器, 接口如下: + + public interface CloudPhoneClipboardListener { + void onClipboardChange(byte[] data); + } + ``` + +- 调用示例 + + ```java + cloudPhone.registerClipboardListener( + new CloudPhoneClipboardListener() { + @Override + public void onClipboardChange(byte[] data) { + // todo + } + } + ); + ``` + +#### 4.14 发送剪切板内容 + +- 接口介绍 + + void sendClipboardData(byte[] data); + +- 功能描述 + + 将真机剪切板内容设置到云手机剪切板。 + +- 调用示例 + + ```java + String clipboard = "clipboard"; + cloudPhone.sendClipboardData(clipboard.getBytes()); + ``` + +#### 4.15 获取网络时延 - 接口介绍 @@ -423,7 +473,7 @@ implementation 'org.bouncycastle:bcprov-jdk15to18:1.71' cloudPhone.getRtt(); -#### 4.14 双向通道 数据发送接口(支持登录、支付场景) +#### 4.16 双向通道 数据发送接口(支持登录、支付场景) - 接口介绍 @@ -433,7 +483,7 @@ implementation 'org.bouncycastle:bcprov-jdk15to18:1.71' 发送数据给云手机中运行的游戏或应用 -#### 4.15 双向通道 数据接收监听接口(支持登录、支付场景) +#### 4.17 双向通道 数据接收监听接口(支持登录、支付场景) - 接口介绍 diff --git a/app/src/main/java/com/huawei/cloudapp/ui/CasCloudPhoneActivity.java b/app/src/main/java/com/huawei/cloudapp/ui/CasCloudPhoneActivity.java index b77f3e6..0322946 100644 --- a/app/src/main/java/com/huawei/cloudapp/ui/CasCloudPhoneActivity.java +++ b/app/src/main/java/com/huawei/cloudapp/ui/CasCloudPhoneActivity.java @@ -18,6 +18,9 @@ package com.huawei.cloudapp.ui; import android.annotation.SuppressLint; import android.app.Activity; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -58,6 +61,7 @@ import com.huawei.cloudapp.utils.CasAdaptPhoneUtils; import com.huawei.cloudapp.utils.CasCommonUtils; import com.huawei.cloudapp.utils.CasHttpUtils; import com.huawei.cloudphone.api.CloudAppDataListener; +import com.huawei.cloudphone.api.CloudPhoneClipboardListener; import com.huawei.cloudphone.api.CloudPhoneManager; import com.huawei.cloudphone.api.CloudPhoneOrientationChangeListener; import com.huawei.cloudphone.api.CloudPhoneParas; @@ -285,12 +289,8 @@ public class CasCloudPhoneActivity extends FragmentActivity { mCloudPhone.registerCloudPhoneStateListener(new CloudPhoneStateListenerImpl()); mCloudPhone.registerOnOrientationChangeListener(new CloudPhoneOrientationListener()); - mCloudPhone.registerCloudAppDataListener(new CloudAppDataListener() { - @Override - public void onRecvCloudAppData(byte[] data) { - CASLog.i(TAG, "onRecvCloudAppData, data size: %d", data.length); - } - }); + mCloudPhone.registerCloudAppDataListener(new CloudAppDataListenerImpl()); + mCloudPhone.registerClipboardListener(new CloudPhoneClipboardListenerImpl()); if (mMediaConfig == null) { mMediaConfig = new HashMap(); @@ -396,6 +396,21 @@ public class CasCloudPhoneActivity extends FragmentActivity { message.what = MSG_SHOW_TRAIL_PLAY_TIMEOUT; handler.sendMessage(message); } + + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + ClipboardManager clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); + if (clipboardManager.hasPrimaryClip() && clipboardManager.getPrimaryClip().getItemCount() > 0) { + CharSequence charSequence = clipboardManager.getPrimaryClip().getItemAt(0).getText(); + try { + mCloudPhone.sendClipboardData(charSequence.toString().getBytes()); + } catch (Exception e) { + CASLog.i(TAG, "failed to send clipboard data " + e.getMessage()); + } + } + } + }, 100); } /** @@ -872,6 +887,24 @@ public class CasCloudPhoneActivity extends FragmentActivity { } } + class CloudAppDataListenerImpl implements CloudAppDataListener { + + @Override + public void onRecvCloudAppData(byte[] data) { + } + } + + class CloudPhoneClipboardListenerImpl implements CloudPhoneClipboardListener { + + @Override + public void onClipboardChange(byte[] data) { + String clipboardText = new String(data); + ClipboardManager clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clipData = ClipData.newPlainText(null, clipboardText); + clipboardManager.setPrimaryClip(clipData); + } + } + private CasConnectInfo getCasConnectorInfo(String ip, String port, String sessionId, diff --git a/cloudphone/src/main/java/com/huawei/cloudphone/api/CloudPhoneClipboardListener.java b/cloudphone/src/main/java/com/huawei/cloudphone/api/CloudPhoneClipboardListener.java new file mode 100644 index 0000000..a48a08f --- /dev/null +++ b/cloudphone/src/main/java/com/huawei/cloudphone/api/CloudPhoneClipboardListener.java @@ -0,0 +1,22 @@ +/* + * Copyright 2023 Huawei Cloud Computing Technology Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.huawei.cloudphone.api; + +public interface CloudPhoneClipboardListener { + + void onClipboardChange(byte[] data); +} \ No newline at end of file diff --git a/cloudphone/src/main/java/com/huawei/cloudphone/api/ICloudPhone.java b/cloudphone/src/main/java/com/huawei/cloudphone/api/ICloudPhone.java index 36c8a48..a082031 100644 --- a/cloudphone/src/main/java/com/huawei/cloudphone/api/ICloudPhone.java +++ b/cloudphone/src/main/java/com/huawei/cloudphone/api/ICloudPhone.java @@ -126,6 +126,19 @@ public interface ICloudPhone { */ void registerPermissionRequestListener(CloudPhonePermissionRequestListener listener); + /** + * 发送剪切板数据 + * @param data + */ + void sendClipboardData(byte[] data); + + /** + * 设置剪切板监听器 + * + * @param listener + */ + void registerClipboardListener(CloudPhoneClipboardListener listener); + /** * 获取网络时延 * diff --git a/cloudphone/src/main/java/com/huawei/cloudphone/apiimpl/CloudPhoneImeMgr.java b/cloudphone/src/main/java/com/huawei/cloudphone/apiimpl/CloudPhoneImeMgr.java index 16a07a2..ea7b8ee 100644 --- a/cloudphone/src/main/java/com/huawei/cloudphone/apiimpl/CloudPhoneImeMgr.java +++ b/cloudphone/src/main/java/com/huawei/cloudphone/apiimpl/CloudPhoneImeMgr.java @@ -20,6 +20,7 @@ import android.widget.EditText; import android.widget.PopupWindow; import android.widget.RelativeLayout; +import com.huawei.cloudphone.api.CloudPhoneClipboardListener; import com.huawei.cloudphone.common.CASLog; public class CloudPhoneImeMgr { @@ -34,6 +35,9 @@ public class CloudPhoneImeMgr { private static final int IME_MSG_SHOW = 0; private static final int IME_MSG_HIDE = 1; private static final int IME_MSG_TEXT = 2; + private static final int IME_KEY_EVENT = 3; + private static final int IME_PASTE_FROM_CLOUD = 6; + private static final int IME_PASTE_TO_CLOUD = 7; private static final int IME_MSG_HEADER_LEN = 3; private ViewGroup mRootViewGroup; @@ -42,6 +46,7 @@ public class CloudPhoneImeMgr { private EditText mImeEditText; private PopupWindow mPopWindow; private CloudPhoneTextWatchListener mTextWatchListener; + private CloudPhoneClipboardListener mClipboardListener; @SuppressLint("Range") public CloudPhoneImeMgr(Context context, ViewGroup viewGroup) { @@ -162,11 +167,13 @@ public class CloudPhoneImeMgr { @Override public void run() { switch (type) { - case IME_MSG_SHOW: - showKeyBoard(true, finalText); - break; - case IME_MSG_HIDE: - showKeyBoard(false, null); +// case IME_MSG_SHOW: +// showKeyBoard(true, finalText); +// break; +// case IME_MSG_HIDE: +// showKeyBoard(false, null); + case IME_PASTE_FROM_CLOUD: + setClipBoard(finalText); default: break; } @@ -178,6 +185,22 @@ public class CloudPhoneImeMgr { mTextWatchListener = listener; } + public void setClipboardListener(CloudPhoneClipboardListener listener) { + mClipboardListener = listener; + } + + public void sendClipboardData(byte[] data) { + byte[] msg = new byte[IME_MSG_HEADER_LEN + data.length]; + msg[0] = IME_PASTE_TO_CLOUD; + msg[1] = (byte) ((data.length >> 8) & 0xFF); + msg[2] = (byte) (data.length & 0XFF); + + System.arraycopy(data, 0, msg, 3, data.length); + if (mTextWatchListener != null) { + mTextWatchListener.onTextChange(msg); + } + } + private void showKeyBoard(boolean isShow, String text) { if (isShow) { this.show(text); @@ -186,6 +209,12 @@ public class CloudPhoneImeMgr { } } + private void setClipBoard(String text) { + if (text != null && mClipboardListener != null) { + mClipboardListener.onClipboardChange(text.getBytes()); + } + } + private int dip2px(float dipValue) { final float scale = mContext.getResources().getDisplayMetrics().density; return (int) (dipValue * scale + 0.5f); diff --git a/cloudphone/src/main/java/com/huawei/cloudphone/apiimpl/CloudPhoneImpl.java b/cloudphone/src/main/java/com/huawei/cloudphone/apiimpl/CloudPhoneImpl.java index 6eef98b..582d22a 100644 --- a/cloudphone/src/main/java/com/huawei/cloudphone/apiimpl/CloudPhoneImpl.java +++ b/cloudphone/src/main/java/com/huawei/cloudphone/apiimpl/CloudPhoneImpl.java @@ -38,6 +38,7 @@ import android.widget.FrameLayout; import com.huawei.cloudphone.BuildConfig; import com.huawei.cloudphone.api.CloudAppDataListener; +import com.huawei.cloudphone.api.CloudPhoneClipboardListener; import com.huawei.cloudphone.api.CloudPhoneOrientationChangeListener; import com.huawei.cloudphone.api.CloudPhoneParas; import com.huawei.cloudphone.api.CloudPhoneParas.DisplayMode; @@ -113,6 +114,7 @@ public class CloudPhoneImpl implements ICloudPhone { private volatile boolean mIsReconnectTaskRun = false; private CloudPhoneStateListener mStateListener = null; private CloudPhoneOrientationChangeListener mOrientationChangeListener = null; + private CloudPhoneClipboardListener mClipboardListener = null; private CloudPhonePermissionRequestListener mPermissionListener = null; private CloudPhoneVirtualDevDataListener mVirtualDevDataListener = null; private CloudAppDataListener mChannelDataListener = null; @@ -306,6 +308,11 @@ public class CloudPhoneImpl implements ICloudPhone { mPermissionListener = listener; } + @Override + public void registerClipboardListener(CloudPhoneClipboardListener listener) { + mClipboardListener = listener; + } + @Override public void sendVirtualDeviceData(byte devType, byte[] data) { if (mProccessor != null) { @@ -322,6 +329,13 @@ public class CloudPhoneImpl implements ICloudPhone { deviceProtocol.processPermissionResult((short) requestCode, grantResults); } + @Override + public void sendClipboardData(byte[] data) { + if (mImeMgr != null) { + mImeMgr.sendClipboardData(data); + } + } + @Override public int getRtt() { if (mProccessor != null) { @@ -516,6 +530,7 @@ public class CloudPhoneImpl implements ICloudPhone { mImeMgr = new CloudPhoneImeMgr(mContext, views); mImeMgr.setTextWatchListener(new TextWatchListener()); + mImeMgr.setClipboardListener(mClipboardListener); } }); } -- Gitee