From d9554f7571c2b28d69fcba90a69329bf5b44e94d Mon Sep 17 00:00:00 2001 From: zher52 Date: Sun, 26 Dec 2021 19:04:17 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90android=E7=AB=AF=E5=9F=BA?= =?UTF-8?q?=E6=9C=AC=E5=8A=9F=E8=83=BD=E5=8D=87=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/android/Trtc.java | 55 ---- .../com/tencent/trtc/CordovaEventKit.java | 45 +++ .../com/tencent/trtc/CustomVideoView.java | 132 +++++++++ .../java/com/tencent/trtc/MessageObject.java | 10 + .../trtc}/TRTCBaseActivity.java | 2 +- .../java/com/tencent/trtc/TrtcPlugin.java | 86 ++++++ .../trtc/debug/GenerateTestUserSig.java | 280 ------------------ .../java/com/tencent/trtc/event/Events.java | 54 ++++ .../java/com/tencent/trtc/event/Listener.java | 7 + .../trtc/message/LayoutChangeMessage.java | 28 ++ .../tencent/trtc/videocall/FloatingView.java | 193 ------------ .../com/tencent/trtc/videocall/UserInfo.java | 67 +++++ .../trtc/videocall/VideoCallingActivity.java | 179 +++++------ .../res/layout/custom_video_view_layout.xml | 24 ++ .../res/layout/videocall_activity_calling.xml | 98 +++--- .../res/layout/videocall_popup_layout.xml | 18 -- .../videocall_view_floating_default.xml | 12 - 17 files changed, 584 insertions(+), 706 deletions(-) delete mode 100644 src/android/Trtc.java create mode 100644 src/android/java/com/tencent/trtc/CordovaEventKit.java create mode 100644 src/android/java/com/tencent/trtc/CustomVideoView.java create mode 100644 src/android/java/com/tencent/trtc/MessageObject.java rename src/android/java/com/{example/basic => tencent/trtc}/TRTCBaseActivity.java (98%) create mode 100644 src/android/java/com/tencent/trtc/TrtcPlugin.java delete mode 100644 src/android/java/com/tencent/trtc/debug/GenerateTestUserSig.java create mode 100644 src/android/java/com/tencent/trtc/event/Events.java create mode 100644 src/android/java/com/tencent/trtc/event/Listener.java create mode 100644 src/android/java/com/tencent/trtc/message/LayoutChangeMessage.java delete mode 100644 src/android/java/com/tencent/trtc/videocall/FloatingView.java create mode 100644 src/android/java/com/tencent/trtc/videocall/UserInfo.java create mode 100644 src/android/res/layout/custom_video_view_layout.xml delete mode 100644 src/android/res/layout/videocall_popup_layout.xml delete mode 100644 src/android/res/layout/videocall_view_floating_default.xml diff --git a/src/android/Trtc.java b/src/android/Trtc.java deleted file mode 100644 index 3557f83..0000000 --- a/src/android/Trtc.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.chuwa.cordova.trtc; - -import android.app.Activity; -import android.content.Intent; - -import com.tencent.trtc.videocall.VideoCallingEnterActivity; -import com.tencent.trtc.videocall.VideoCallingActivity; - -import org.apache.cordova.CordovaInterface; -import org.apache.cordova.CordovaPlugin; -import org.apache.cordova.CallbackContext; - -import org.apache.cordova.CordovaWebView; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - - -public class Trtc extends CordovaPlugin { - - static final String ACTION_SHOW_CREATE_PAGE = "showCreatePage"; // for test - static final String ACTION_JOIN_CHANNEL = "joinChannel"; - - @Override - public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { - Activity activity = this.cordova.getActivity(); - -// if (ACTION_SHOW_CREATE_PAGE.equals(action)) { -// Intent intent = new Intent(activity, VideoCallingEnterActivity.class); -// cordova.startActivityForResult(this, intent, 666); -// } else - if (ACTION_JOIN_CHANNEL.equals(action)) { - Intent intent = new Intent(activity, VideoCallingActivity.class); - JSONObject arg = args.getJSONObject(0); - String ROOM_ID = arg.getString("ROOM_ID"); - String USER_ID = arg.getString("USER_ID"); - int SDK_APP_ID = arg.getInt("SDK_APP_ID"); - String USER_SIG = arg.getString("USER_SIG"); - intent.putExtra("room_id", ROOM_ID); - intent.putExtra("user_id", USER_ID); - intent.putExtra("sdk_app_id", SDK_APP_ID); - intent.putExtra("user_sig", USER_SIG); - cordova.startActivityForResult(this, intent, 666); - } - - return false; - } - - @Override - public void initialize(CordovaInterface cordova, CordovaWebView webView) { - super.initialize(cordova, webView); - } - - -} diff --git a/src/android/java/com/tencent/trtc/CordovaEventKit.java b/src/android/java/com/tencent/trtc/CordovaEventKit.java new file mode 100644 index 0000000..5e7ef16 --- /dev/null +++ b/src/android/java/com/tencent/trtc/CordovaEventKit.java @@ -0,0 +1,45 @@ +package com.tencent.trtc; + +import org.apache.cordova.CordovaPlugin; +import org.json.JSONArray; +import org.json.JSONObject; + +public class CordovaEventKit { + public static CordovaEventKit kit = null; + private CordovaPlugin plugin; + + + private CordovaEventKit(CordovaPlugin plugin) { + this.plugin = plugin; + } + + public static void init(CordovaPlugin plugin){ + if(CordovaEventKit.kit == null){ + CordovaEventKit.kit = new CordovaEventKit(plugin); + } + } + + + public void fireEvent(String event, JSONArray obj){ + this.fireEvent(event,obj == null ? null obj.toString()); + } + + public void fireEvent(String event, JSONObject obj){ + this.fireEvent(event,obj == null ? null :obj.toString()); + } + + public void fireEvent(String event, String obj){ + if (plugin == null || event == null || obj == null) { + return; + } + event = event.replace('\'','_'); + String format = "window.cordova.plugin.trtc.fireEvent('%s',%s);"; + final String js = String.format(format,event, obj); + plugin.cordova.getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + plugin.webView.loadUrl("javascript:" + js); + } + }); + } +} diff --git a/src/android/java/com/tencent/trtc/CustomVideoView.java b/src/android/java/com/tencent/trtc/CustomVideoView.java new file mode 100644 index 0000000..f9ac607 --- /dev/null +++ b/src/android/java/com/tencent/trtc/CustomVideoView.java @@ -0,0 +1,132 @@ +package com.tencent.trtc; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.tencent.rtmp.ui.TXCloudVideoView; +import com.tencent.trtc.event.Events; +import com.tencent.trtc.videocall.UserInfo; + +public class CustomVideoView extends RelativeLayout { + + private Context mContext; + private View mView; + + private TXCloudVideoView videoView; + private TextView titleView; + + private UserInfo userInfo; + + private boolean alwaysHide = false; + private boolean mainView; + + + public CustomVideoView(Context context) { + this(context,null); + } + + public CustomVideoView(Context context, AttributeSet attrs) { + this(context, attrs,0); + } + + public CustomVideoView(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr,0); + } + + public CustomVideoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(context, attrs); + } + + private void init(Context context, AttributeSet attrs) { + mContext = context; + LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + mView = inflater.inflate(getId("custom_video_view_layout", "layout"), this, true); + videoView = (TXCloudVideoView) findViewById(getId("video", "id")); + titleView = (TextView) findViewById(getId("title","id")); + } + + + private int getId(String idName, String type) { + return getResources().getIdentifier(idName, type, mContext.getPackageName()); + } + + public void changeUser(TRTCCloud mTRTCCloud, UserInfo userInfo) { + if(userInfo == null){ + setVisibility(View.GONE); + }else { + setVisibility(alwaysHide?INVISIBLE:VISIBLE); + } +// if(this.userInfo != null){ +// if(this.userInfo.isLocal()){ +// mTRTCCloud.stopLocalPreview(); +// mTRTCCloud.stopLocalAudio(); +//// }else{ +//// mTRTCCloud.stopRemoteView(this.userInfo.getPersonid()); +// } +// } + if(isChanged(userInfo)){ + this.userInfo = userInfo; + if(this.userInfo != null){ + if(this.userInfo.isLocal()){ + mTRTCCloud.startLocalPreview(userInfo.isFrontCamera(), videoView); + mTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_SPEECH); + } else { + mTRTCCloud.startRemoteView(this.userInfo.getPersonid(), TRTCCloudDef.TRTC_VIDEO_STREAM_TYPE_SMALL, videoView); + } + if(this.userInfo.getDisplayName() == null || this.userInfo.getDisplayName().length() == 0){ + this.titleView.setText(this.userInfo.getPersonid()); + }else { + this.titleView.setText(this.userInfo.getDisplayName()); + } + this.titleView.setVisibility(VISIBLE); + }else { + this.titleView.setVisibility(INVISIBLE); + } + } + } + + private boolean isChanged(UserInfo userInfo){ + return (this.userInfo == null && userInfo !=null) || + (this.userInfo != null && !this.userInfo.equals(userInfo)); + } + + public boolean isAlwaysHide() { + return alwaysHide; + } + + public CustomVideoView setAlwaysHide(boolean alwaysHide) { + this.alwaysHide = alwaysHide; + return this; + } + + public boolean isMainView() { + return mainView; + } + + public CustomVideoView setMainView(boolean mainView) { + this.mainView = mainView; + if(!mainView){ + Events.addListener("subview.always.hide",(extra)->{ + this.alwaysHide = extra.getBoolean("alwaysHide",false); + this.setVisibility(alwaysHide?INVISIBLE:VISIBLE); + }); + } + Events.addListener("userinfo.update",(extra -> { + if(this.userInfo !=null && this.userInfo.getDisplayName() == null + && this.userInfo.getDisplayName().length() == 0 + && extra.getString("personid").equals(this.userInfo.getPersonid())){ + this.titleView.setText(extra.getString("displayName",this.userInfo.getDisplayName())); + } + })); + return this; + } + + public UserInfo getUserInfo() { + return userInfo; + } +} diff --git a/src/android/java/com/tencent/trtc/MessageObject.java b/src/android/java/com/tencent/trtc/MessageObject.java new file mode 100644 index 0000000..9bcabf9 --- /dev/null +++ b/src/android/java/com/tencent/trtc/MessageObject.java @@ -0,0 +1,10 @@ +package com.tencent.trtc; + +import org.json.JSONObject; + +public interface MessageObject { + + String getEvent(); + + JSONObject toJson(); +} diff --git a/src/android/java/com/example/basic/TRTCBaseActivity.java b/src/android/java/com/tencent/trtc/TRTCBaseActivity.java similarity index 98% rename from src/android/java/com/example/basic/TRTCBaseActivity.java rename to src/android/java/com/tencent/trtc/TRTCBaseActivity.java index 52cb357..4e015b0 100644 --- a/src/android/java/com/example/basic/TRTCBaseActivity.java +++ b/src/android/java/com/tencent/trtc/TRTCBaseActivity.java @@ -1,4 +1,4 @@ -package android.java.com.example.basic; +package com.tencent.trtc; import android.Manifest; import android.content.pm.PackageManager; diff --git a/src/android/java/com/tencent/trtc/TrtcPlugin.java b/src/android/java/com/tencent/trtc/TrtcPlugin.java new file mode 100644 index 0000000..27147ef --- /dev/null +++ b/src/android/java/com/tencent/trtc/TrtcPlugin.java @@ -0,0 +1,86 @@ +package com.tencent.trtc; + +import android.app.Activity; +import android.content.Intent; +import android.util.Log; + +import com.tencent.trtc.CordovaEventKit; +import com.tencent.trtc.event.Events; +import com.tencent.trtc.videocall.VideoCallingEnterActivity; +import com.tencent.trtc.videocall.VideoCallingActivity; + +import org.apache.cordova.CordovaInterface; +import org.apache.cordova.CordovaPlugin; +import org.apache.cordova.CallbackContext; + +import org.apache.cordova.CordovaWebView; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.lang.reflect.Method; + + +public class TrtcPlugin extends CordovaPlugin { + private static final String TAG = TrtcPlugin.class.getSimpleName(); + + /** + * 加入会议 + * @param args + * @param callbackContext + * @throws JSONException + */ + public void joinChannel(JSONArray args, CallbackContext callbackContext) throws JSONException { + Intent intent = new Intent(this.cordova.getActivity(), VideoCallingActivity.class); + JSONObject arg = args.getJSONObject(0); + String ROOM_ID = arg.getString("ROOM_ID"); + String USER_ID = arg.getString("USER_ID"); + int SDK_APP_ID = arg.getInt("SDK_APP_ID"); + String USER_SIG = arg.getString("USER_SIG"); + intent.putExtra("room_id", ROOM_ID); + intent.putExtra("user_id", USER_ID); + intent.putExtra("sdk_app_id", SDK_APP_ID); + intent.putExtra("user_sig", USER_SIG); + cordova.startActivityForResult(this, intent, 666); + } + + + public void userInfoChange(JSONArray args,CallbackContext callbackContext) throws JSONException{ + JSONObject object = args.getJSONObject(0); + if(object != null){ + Events.fireEvent("userinfo.update",extra -> { + try { + extra.putString("personid",object.getString("personid")); + extra.putString("displayName",object.getString("displayName")); + } catch (JSONException e) { + e.printStackTrace(); + } + }); + } + } + + @Override + public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { + cordova.getThreadPool().execute(new Runnable() { + @Override + public void run() { + try { + Method method = TrtcPlugin.class.getDeclaredMethod(action, JSONArray.class, CallbackContext.class); + method.invoke(TrtcPlugin.this, args, callbackContext); + } catch (Exception e) { + Log.e(TAG, e.toString()); + } + } + }); + return true; + } + + + @Override + public void initialize(CordovaInterface cordova, CordovaWebView webView) { + super.initialize(cordova, webView); + CordovaEventKit.init(this); + } + + +} diff --git a/src/android/java/com/tencent/trtc/debug/GenerateTestUserSig.java b/src/android/java/com/tencent/trtc/debug/GenerateTestUserSig.java deleted file mode 100644 index 0826965..0000000 --- a/src/android/java/com/tencent/trtc/debug/GenerateTestUserSig.java +++ /dev/null @@ -1,280 +0,0 @@ -package com.tencent.trtc.debug; - - -import android.util.Base64; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.UnsupportedEncodingException; -import java.nio.charset.Charset; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.zip.Deflater; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; - -/** - * Module: GenerateTestUserSig - * - * Function: 用于生成测试用的 UserSig,UserSig 是腾讯云为其云服务设计的一种安全保护签名。 - * 其计算方法是对 SDKAppID、UserID 和 EXPIRETIME 进行加密,加密算法为 HMAC-SHA256。 - * - * Attention: 请不要将如下代码发布到您的线上正式版本的 App 中,原因如下: - * - * 本文件中的代码虽然能够正确计算出 UserSig,但仅适合快速调通 SDK 的基本功能,不适合线上产品, - * 这是因为客户端代码中的 SECRETKEY 很容易被反编译逆向破解,尤其是 Web 端的代码被破解的难度几乎为零。 - * 一旦您的密钥泄露,攻击者就可以计算出正确的 UserSig 来盗用您的腾讯云流量。 - * - * 正确的做法是将 UserSig 的计算代码和加密密钥放在您的业务服务器上,然后由 App 按需向您的服务器获取实时算出的 UserSig。 - * 由于破解服务器的成本要高于破解客户端 App,所以服务器计算的方案能够更好地保护您的加密密钥。 - * - * Reference:https://cloud.tencent.com/document/product/647/17275#Server - */ - -/** - * Module: GenerateTestUserSig - * - * Description: generates UserSig for testing. UserSig is a security signature designed by Tencent Cloud for its cloud services. - * It is calculated based on `SDKAppID`, `UserID`, and `EXPIRETIME` using the HMAC-SHA256 encryption algorithm. - * - * Attention: do not use the code below in your commercial app. This is because: - * - * The code may be able to calculate UserSig correctly, but it is only for quick testing of the SDK’s basic features, not for commercial apps. - * `SECRETKEY` in client code can be easily decompiled and reversed, especially on web. - * Once your key is disclosed, attackers will be able to steal your Tencent Cloud traffic. - * - * The correct method is to deploy the `UserSig` calculation code and encryption key on your project server so that your app can request from your server a `UserSig` that is calculated whenever one is needed. - * Given that it is more difficult to hack a server than a client app, server-end calculation can better protect your key. - * - * Reference: https://cloud.tencent.com/document/product/647/17275#Server - */ -public class GenerateTestUserSig { - - /** - * 配置为CDN发布、混流的域名 - * - */ - - /** - * Domain name for CDN publishing and stream mixing - */ - public static final String CDN_DOMAIN_NAME = "testuser"; - - /** - * CDN发布功能 混流bizId - */ - - /** - * `bizId` for CDN publishing and stream mixing - */ - public static final int BIZID = 111; - - /** - * CDN发布功能 混流appId - */ - - /** - * `appId` for CDN publishing and stream mixing - */ - public static final int APPID = 111; - - /** - * 腾讯云 SDKAppId,需要替换为您自己账号下的 SDKAppId。 - * - * 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ) 创建应用,即可看到 SDKAppId, - * 它是腾讯云用于区分客户的唯一标识。 - */ - - /** - * Tencent Cloud `SDKAppID`. Set it to the `SDKAppID` of your account. - * - * You can view your `SDKAppID` after creating an application in the [TRTC console](https://console.cloud.tencent.com/rav). - * `SDKAppID` uniquely identifies a Tencent Cloud account. - */ - public static final int SDKAPPID = 1400593044; - - /** - * 签名过期时间,建议不要设置的过短 - *

- * 时间单位:秒 - * 默认时间:7 x 24 x 60 x 60 = 604800 = 7 天 - */ - - /** - * Signature validity period, which should not be set too short - *

- * Unit: second - * Default value: 604800 (7 days) - */ - private static final int EXPIRETIME = 604800; - - - /** - * 计算签名用的加密密钥,获取步骤如下: - * - * step1. 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ),如果还没有应用就创建一个, - * step2. 单击应用信息,并进一步找到“快速上手”部分。 - * step3. 点击“复制密钥”按钮,复制密钥,请将其拷贝并复制到如下的变量中 - * - * 注意:该方案仅适用于调试Demo,正式上线前请将 UserSig 计算代码和密钥迁移到您的后台服务器上,以避免加密密钥泄露导致的流量盗用。 - * 文档:https://cloud.tencent.com/document/product/647/17275#Server - */ - - /** - * Follow the steps below to obtain the key required for UserSig calculation. - * - * Step 1. Log in to the [TRTC console](https://console.cloud.tencent.com/rav), and create an application if you don’t have one. - * Step 2. Find your application, click “Application Info”, and click the “Quick Start” tab. - * Step 3. Copy and paste the key to the code, as shown below. - * - * Note: this method is for testing only. Before commercial launch, please migrate the UserSig calculation code and key to your backend server to prevent key disclosure and traffic stealing. - * Reference: https://cloud.tencent.com/document/product/647/17275#Server - */ - public static final String SECRETKEY = "f814a0480cfa95a3ffffd8891844f3cd36888166dbef5347303043744f247c06"; - - /** - * 计算 UserSig 签名 - * - * 函数内部使用 HMAC-SHA256 非对称加密算法,对 SDKAPPID、userId 和 EXPIRETIME 进行加密。 - * - * @note: 请不要将如下代码发布到您的线上正式版本的 App 中,原因如下: - * - * 本文件中的代码虽然能够正确计算出 UserSig,但仅适合快速调通 SDK 的基本功能,不适合线上产品, - * 这是因为客户端代码中的 SECRETKEY 很容易被反编译逆向破解,尤其是 Web 端的代码被破解的难度几乎为零。 - * 一旦您的密钥泄露,攻击者就可以计算出正确的 UserSig 来盗用您的腾讯云流量。 - * - * 正确的做法是将 UserSig 的计算代码和加密密钥放在您的业务服务器上,然后由 App 按需向您的服务器获取实时算出的 UserSig。 - * 由于破解服务器的成本要高于破解客户端 App,所以服务器计算的方案能够更好地保护您的加密密钥。 - * - * 文档:https://cloud.tencent.com/document/product/647/17275#Server - */ - - /** - * Calculating UserSig - * - * The asymmetric encryption algorithm HMAC-SHA256 is used in the function to calculate UserSig based on `SDKAppID`, `UserID`, and `EXPIRETIME`. - * - * @note: do not use the code below in your commercial app. This is because: - * - * The code may be able to calculate UserSig correctly, but it is only for quick testing of the SDK’s basic features, not for commercial apps. - * `SECRETKEY` in client code can be easily decompiled and reversed, especially on web. - * Once your key is disclosed, attackers will be able to steal your Tencent Cloud traffic. - * - * The correct method is to deploy the `UserSig` calculation code on your project server so that your app can request from your server a `UserSig` that is calculated whenever one is needed. - * Given that it is more difficult to hack a server than a client app, server-end calculation can better protect your key. - * - * Reference: https://cloud.tencent.com/document/product/647/17275#Server - */ - public static String genTestUserSig(String userId) { - return GenTLSSignature(SDKAPPID, userId, EXPIRETIME, null, SECRETKEY); - } - - /** - * 生成 tls 票据 - * - * @param sdkappid 应用的 appid - * @param userId 用户 id - * @param expire 有效期,单位是秒 - * @param userbuf 默认填写null - * @param priKeyContent 生成 tls 票据使用的私钥内容 - * @return 如果出错,会返回为空,或者有异常打印,成功返回有效的票据 - */ - - /** - * Generating a TLS Ticket - * - * @param sdkappid `appid` of your application - * @param userId User ID - * @param expire Validity period, in seconds - * @param userbuf `null` by default - * @param priKeyContent Private key required for generating a TLS ticket - * @return If an error occurs, an empty string will be returned or exceptions printed. If the operation succeeds, a valid ticket will be returned. - */ - private static String GenTLSSignature(long sdkappid, String userId, long expire, byte[] userbuf, String priKeyContent) { - long currTime = System.currentTimeMillis() / 1000; - JSONObject sigDoc = new JSONObject(); - try { - sigDoc.put("TLS.ver", "2.0"); - sigDoc.put("TLS.identifier", userId); - sigDoc.put("TLS.sdkappid", sdkappid); - sigDoc.put("TLS.expire", expire); - sigDoc.put("TLS.time", currTime); - } catch (JSONException e) { - e.printStackTrace(); - } - - String base64UserBuf = null; - if (null != userbuf) { - base64UserBuf = Base64.encodeToString(userbuf, Base64.NO_WRAP); - try { - sigDoc.put("TLS.userbuf", base64UserBuf); - } catch (JSONException e) { - e.printStackTrace(); - } - } - String sig = hmacsha256(sdkappid, userId, currTime, expire, priKeyContent, base64UserBuf); - if (sig.length() == 0) { - return ""; - } - try { - sigDoc.put("TLS.sig", sig); - } catch (JSONException e) { - e.printStackTrace(); - } - Deflater compressor = new Deflater(); - compressor.setInput(sigDoc.toString().getBytes(Charset.forName("UTF-8"))); - compressor.finish(); - byte[] compressedBytes = new byte[2048]; - int compressedBytesLength = compressor.deflate(compressedBytes); - compressor.end(); - return new String(base64EncodeUrl(Arrays.copyOfRange(compressedBytes, 0, compressedBytesLength))); - } - - - private static String hmacsha256(long sdkappid, String userId, long currTime, long expire, String priKeyContent, String base64Userbuf) { - String contentToBeSigned = "TLS.identifier:" + userId + "\n" - + "TLS.sdkappid:" + sdkappid + "\n" - + "TLS.time:" + currTime + "\n" - + "TLS.expire:" + expire + "\n"; - if (null != base64Userbuf) { - contentToBeSigned += "TLS.userbuf:" + base64Userbuf + "\n"; - } - try { - byte[] byteKey = priKeyContent.getBytes("UTF-8"); - Mac hmac = Mac.getInstance("HmacSHA256"); - SecretKeySpec keySpec = new SecretKeySpec(byteKey, "HmacSHA256"); - hmac.init(keySpec); - byte[] byteSig = hmac.doFinal(contentToBeSigned.getBytes("UTF-8")); - return new String(Base64.encode(byteSig, Base64.NO_WRAP)); - } catch (UnsupportedEncodingException e) { - return ""; - } catch (NoSuchAlgorithmException e) { - return ""; - } catch (InvalidKeyException e) { - return ""; - } - } - - private static byte[] base64EncodeUrl(byte[] input) { - byte[] base64 = new String(Base64.encode(input, Base64.NO_WRAP)).getBytes(); - for (int i = 0; i < base64.length; ++i) - switch (base64[i]) { - case '+': - base64[i] = '*'; - break; - case '/': - base64[i] = '-'; - break; - case '=': - base64[i] = '_'; - break; - default: - break; - } - return base64; - } - -} diff --git a/src/android/java/com/tencent/trtc/event/Events.java b/src/android/java/com/tencent/trtc/event/Events.java new file mode 100644 index 0000000..2a3b51d --- /dev/null +++ b/src/android/java/com/tencent/trtc/event/Events.java @@ -0,0 +1,54 @@ +package com.tencent.trtc.event; + +import android.os.Bundle; + +import org.json.JSONException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Events { + private static final String PREFIX = "com.tencent.trtc.event"; + private static Map> events = new HashMap(); + public static void fireEvent(String event){ + fireEvent(event,null); + } + public static void fireEvent(String event, Extra extra){ + if(events.containsKey(PREFIX+event)){ + for(Listener listener : events.get(PREFIX+event)){ + Bundle bundle = extra == null ? Bundle.EMPTY: new Bundle(); + if(extra != null){ + extra.extra(bundle); + } + listener.on(extra == null ? Bundle.EMPTY : bundle); + } + } + } + + public static void addListener(String eventName,Listener listener){ + if(!events.containsKey(PREFIX+eventName)){ + events.put(PREFIX+eventName,new ArrayList<>()); + } + List list = events.get(PREFIX+eventName); + if(!list.contains(listener)){ + list.add(listener); + } + } + + public static void removeListener(String eventName,Listener listener){ + if(!events.containsKey(PREFIX+eventName)){ + events.put(PREFIX+eventName,new ArrayList<>()); + } + List list = events.get(PREFIX+eventName); + if(list.contains(listener)){ + list.remove(listener); + } + } + + + public interface Extra{ + public void extra(Bundle extra); + } +} diff --git a/src/android/java/com/tencent/trtc/event/Listener.java b/src/android/java/com/tencent/trtc/event/Listener.java new file mode 100644 index 0000000..e55651b --- /dev/null +++ b/src/android/java/com/tencent/trtc/event/Listener.java @@ -0,0 +1,7 @@ +package com.tencent.trtc.event; + +import android.os.Bundle; + +public interface Listener { + void on(Bundle extra); +} diff --git a/src/android/java/com/tencent/trtc/message/LayoutChangeMessage.java b/src/android/java/com/tencent/trtc/message/LayoutChangeMessage.java new file mode 100644 index 0000000..13dde93 --- /dev/null +++ b/src/android/java/com/tencent/trtc/message/LayoutChangeMessage.java @@ -0,0 +1,28 @@ +package com.tencent.trtc.message; + +import com.tencent.trtc.MessageObject; + +import org.json.JSONObject; + +public class LayoutChangeMessage implements MessageObject { + + private String room; + private String personid; + + + public LayoutChangeMessage(String room, String personid) { + this.room = room; + this.personid = personid; + } + + @Override + public String getEvent() { + return "LayoutChangeMessage"; + } + + @Override + public JSONObject getJson() { + JSONObject obj = new JSONObject(); + return obj; + } +} diff --git a/src/android/java/com/tencent/trtc/videocall/FloatingView.java b/src/android/java/com/tencent/trtc/videocall/FloatingView.java deleted file mode 100644 index 2259163..0000000 --- a/src/android/java/com/tencent/trtc/videocall/FloatingView.java +++ /dev/null @@ -1,193 +0,0 @@ -package com.tencent.trtc.videocall; - -import android.annotation.TargetApi; -import android.content.Context; -import android.graphics.PixelFormat; -import android.graphics.drawable.BitmapDrawable; -import android.os.Build; -import android.util.AttributeSet; -import android.view.GestureDetector; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.widget.FrameLayout; -import android.widget.PopupWindow; - -/** - * 悬浮球,点击可以弹出菜单 - */ -@TargetApi(Build.VERSION_CODES.LOLLIPOP) -public class FloatingView extends FrameLayout implements GestureDetector.OnGestureListener { - - private Context mContext; - private WindowManager mWindowManager; - private GestureDetector mGestureDetector; - private WindowManager.LayoutParams mLayoutParams; - private float mLastX; - private float mLastY; - private PopupWindow mPopupWindow; - private long mTapOutsideTime; - private boolean mIsShowing = false; - - public FloatingView(Context context) { - super(context); - this.mContext = context; - this.mGestureDetector = new GestureDetector(context, this); - } - - public FloatingView(Context context, AttributeSet attrs) { - super(context, attrs); - this.mContext = context; - this.mGestureDetector = new GestureDetector(context, this); - } - - public FloatingView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - this.mContext = context; - this.mGestureDetector = new GestureDetector(context, this); - } - - public FloatingView(Context context, int viewResId) { - super(context); - this.mContext = context; - View.inflate(context, viewResId, this); - this.mGestureDetector = new GestureDetector(context, this); - } - - public void showView(View view) { - showView(view, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT); - } - - public void showView(View view, int width, int height) { - mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); - int type = WindowManager.LayoutParams.TYPE_TOAST; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; - } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) { - type = WindowManager.LayoutParams.TYPE_PHONE; - } - mLayoutParams = new WindowManager.LayoutParams(type); - mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; - mLayoutParams.flags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; - mLayoutParams.width = width; - mLayoutParams.height = height; - mLayoutParams.format = PixelFormat.TRANSLUCENT; - mWindowManager.addView(view, mLayoutParams); - } - - public void hideView() { - if (null != mWindowManager) { - mWindowManager.removeViewImmediate(this); - } - mWindowManager = null; - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - return mGestureDetector.onTouchEvent(event); - } - - @Override - public boolean onDown(MotionEvent e) { - mLastX = e.getRawX(); - mLastY = e.getRawY(); - return false; - } - - @Override - public void onShowPress(MotionEvent e) { - } - - @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - float nowX, nowY, tranX, tranY; - nowX = e2.getRawX(); - nowY = e2.getRawY(); - tranX = nowX - mLastX; - tranY = nowY - mLastY; - mLayoutParams.x += tranX; - mLayoutParams.y += tranY; - mWindowManager.updateViewLayout(this, mLayoutParams); - mLastX = nowX; - mLastY = nowY; - return false; - } - - @Override - public void onLongPress(MotionEvent e) { - } - - @Override - public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - return false; - } - - public void setPopupWindow(int id) { - mPopupWindow = new PopupWindow(this); - mPopupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT); - mPopupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); - mPopupWindow.setTouchable(true); - mPopupWindow.setOutsideTouchable(true); - mPopupWindow.setFocusable(false); - mPopupWindow.setBackgroundDrawable(new BitmapDrawable()); - mPopupWindow.setContentView(LayoutInflater.from(getContext()).inflate(id, null)); - mPopupWindow.setTouchInterceptor(new OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_OUTSIDE) { - mPopupWindow.dismiss(); - mTapOutsideTime = System.currentTimeMillis(); - return true; - } - return false; - } - }); - } - - public View getPopupView() { - return mPopupWindow.getContentView(); - } - - public void setOnPopupItemClickListener(OnClickListener listener) { - if (mPopupWindow == null) - return; - - ViewGroup layout = (ViewGroup) mPopupWindow.getContentView(); - for (int i = 0; i < layout.getChildCount(); i++) { - layout.getChildAt(i).setOnClickListener(listener); - } - } - - public void show() { - if (!mIsShowing) { - showView(this); - } - mIsShowing = true; - } - - public void dismiss() { - if (mIsShowing) { - hideView(); - } - mIsShowing = false; - ViewGroup layout = (ViewGroup) mPopupWindow.getContentView(); - for (int i = 0; i < layout.getChildCount(); i++) { - layout.getChildAt(i).setOnClickListener(null); - } - } - - @Override - public boolean onSingleTapUp(MotionEvent e) { - if (null != mPopupWindow) - mPopupWindow.dismiss(); - if (!(System.currentTimeMillis() - mTapOutsideTime < 80)) { - mPopupWindow.showAtLocation(this, Gravity.NO_GRAVITY, 100, 0); - } - return false; - } - - -} diff --git a/src/android/java/com/tencent/trtc/videocall/UserInfo.java b/src/android/java/com/tencent/trtc/videocall/UserInfo.java new file mode 100644 index 0000000..c37a277 --- /dev/null +++ b/src/android/java/com/tencent/trtc/videocall/UserInfo.java @@ -0,0 +1,67 @@ +package com.tencent.trtc.videocall; + +import androidx.annotation.Nullable; + +public class UserInfo { + String personid; + String displayName; + boolean isLocal; + + boolean frontCamera = true; + + public String getPersonid() { + return personid; + } + + public UserInfo setPersonid(String personid) { + this.personid = personid; + return this; + } + + public String getDisplayName() { + return displayName; + } + + public UserInfo setDisplayName(String displayName) { + this.displayName = displayName; + return this; + } + + public boolean isLocal() { + return isLocal; + } + + public UserInfo setLocal(boolean local) { + isLocal = local; + return this; + } + + public boolean isFrontCamera() { + return frontCamera; + } + + public UserInfo setFrontCamera(boolean frontCamera) { + this.frontCamera = frontCamera; + return this; + } + + + @Override + public int hashCode() { + return getPersonid().hashCode(); + } + + @Override + public boolean equals(@Nullable Object obj) { + if(obj == null){ + return false; + } + if(obj instanceof UserInfo){ + return getPersonid() == null ? ((UserInfo) obj).getPersonid() == null + : getPersonid().equals(((UserInfo) obj).getPersonid()); + }else if(obj instanceof String){ + return getPersonid() == null ? obj == null : getPersonid().equals(obj); + } + return false; + } +} diff --git a/src/android/java/com/tencent/trtc/videocall/VideoCallingActivity.java b/src/android/java/com/tencent/trtc/videocall/VideoCallingActivity.java index 4072c97..992b34a 100644 --- a/src/android/java/com/tencent/trtc/videocall/VideoCallingActivity.java +++ b/src/android/java/com/tencent/trtc/videocall/VideoCallingActivity.java @@ -1,31 +1,31 @@ package com.tencent.trtc.videocall; import android.content.Intent; -import android.net.Uri; -import android.os.Build; import android.os.Bundle; -import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import android.view.View; -import android.widget.Button; -import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; -import android.java.com.example.basic.TRTCBaseActivity; +import com.tencent.trtc.CordovaEventKit; +import com.tencent.trtc.CustomVideoView; +import com.tencent.trtc.TRTCBaseActivity; -import com.tencent.liteav.TXLiteAVCode; import com.tencent.liteav.device.TXDeviceManager; -import com.tencent.rtmp.ui.TXCloudVideoView; import com.tencent.trtc.TRTCCloud; import com.tencent.trtc.TRTCCloudDef; import com.tencent.trtc.TRTCCloudListener; import com.tencent.trtc.debug.Constant; +import com.tencent.trtc.event.Events; + +import org.json.JSONException; +import org.json.JSONObject; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -61,7 +61,7 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli private static final int OVERLAY_PERMISSION_REQ_CODE = 1234; private TextView mTextTitle; - private TXCloudVideoView mTXCVVLocalPreviewView; +// private CustomVideoView mTXCVVLocalPreviewView; private ImageView mImageBack; private ImageView mButtonMuteVideo; private ImageView mButtonMuteAudio; @@ -71,15 +71,17 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli private TRTCCloud mTRTCCloud; private TXDeviceManager mTXDeviceManager; private boolean mIsFrontCamera = true; - private List mRemoteUidList; - private List mRemoteViewList; + private List mUserList; + private List mRemoteViewList; private int mUserCount = 0; private String mRoomId; private String mUserId; private int sdkAppId; private String userSig; + private boolean hideSub; private boolean mAudioRouteFlag = true; - private FloatingView mFloatingView; + + private UserInfo localUserInfo; private int getId(String idName, String type) { return getResources().getIdentifier(idName, type, getPackageName()); @@ -127,7 +129,6 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli // R.id.iv_back mImageBack = findViewById(getId("iv_back", "id")); // R.id.txcvv_main - mTXCVVLocalPreviewView = findViewById(getId("txcvv_main", "id")); // R.id.btn_mute_video mButtonMuteVideo = findViewById(getId("btn_mute_video", "id")); // R.id.btn_mute_audio @@ -146,21 +147,45 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli mButtonSwitchCamera.setOnClickListener(this); mButtonAudioRoute.setOnClickListener(this); - mRemoteUidList = new ArrayList<>(); + mUserList = new ArrayList<>(); + localUserInfo = new UserInfo().setPersonid(mUserId).setLocal(true) + .setDisplayName("我").setFrontCamera(mIsFrontCamera); + mUserList.add(localUserInfo); mRemoteViewList = new ArrayList<>(); -// R.id.trtc_view_1 - mRemoteViewList.add((TXCloudVideoView) findViewById(getId("trtc_view_1", "id"))); - mRemoteViewList.add((TXCloudVideoView) findViewById(getId("trtc_view_2", "id"))); - mRemoteViewList.add((TXCloudVideoView) findViewById(getId("trtc_view_3", "id"))); - mRemoteViewList.add((TXCloudVideoView) findViewById(getId("trtc_view_4", "id"))); - mRemoteViewList.add((TXCloudVideoView) findViewById(getId("trtc_view_5", "id"))); - mRemoteViewList.add((TXCloudVideoView) findViewById(getId("trtc_view_6", "id"))); + for(int i=0;i<7;i++){ + CustomVideoView videoView = ((CustomVideoView) findViewById(getId("trtc_view_"+i, "id"))).setMainView(i == 0); + if(i > 0){ + videoView.setOnClickListener((view)->{ + if(view instanceof CustomVideoView && !((CustomVideoView) view).isMainView()){ + UserInfo mainUser = this.mUserList.get(0); + UserInfo viewUser = ((CustomVideoView) view).getUserInfo(); + Collections.swap(this.mUserList,0,this.mUserList.indexOf(viewUser)); + mTRTCCloud.stopLocalPreview(); + mTRTCCloud.stopLocalAudio(); + mRemoteViewList.get(0).changeUser(mTRTCCloud,viewUser); + ((CustomVideoView) view).changeUser(mTRTCCloud,mainUser); + try { + JSONObject object = new JSONObject(); + object.put("room",mRoomId); + object.put("personid",viewUser.getPersonid()); + CordovaEventKit.kit.fireEvent("LayoutChangeMessage",object); + } catch (JSONException e) { + e.printStackTrace(); + } + } + }); + } + mRemoteViewList.add(videoView); + } + Events.fireEvent("subview.always.hide",(extra)->extra.putBoolean("alwaysHide",false)); -// R.layout.videocall_view_floating_default - mFloatingView = new FloatingView(getApplicationContext(), getId("videocall_view_floating_default", "layout")); -// R.layout.videocall_popup_layout - mFloatingView.setPopupWindow(getId("videocall_popup_layout", "layout")); - mFloatingView.setOnPopupItemClickListener(this); + Events.addListener("userinfo.update",(extra -> { + String user = extra.getString("personid"); + int index = this.mUserList.indexOf(user); + if(index > -1){ + this.mUserList.get(index).setDisplayName(extra.getString("displayName")); + } + })); } private void enterRoom() { @@ -174,23 +199,26 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli trtcParams.roomId = Integer.parseInt(mRoomId); trtcParams.userSig = this.userSig; - mTRTCCloud.startLocalPreview(mIsFrontCamera, mTXCVVLocalPreviewView); - mTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_SPEECH); + mRemoteViewList.get(0).changeUser(mTRTCCloud, mUserList.get(0)); mTRTCCloud.enterRoom(trtcParams, TRTCCloudDef.TRTC_APP_SCENE_VIDEOCALL); + JSONObject object = new JSONObject(); + try { + object.put("room",mRoomId); + object.put("personid",mUserList.get(0).getPersonid()); + CordovaEventKit.kit.fireEvent("LayoutChangeMessage",object); + } catch (JSONException e) { + e.printStackTrace(); + } } @Override protected void onStop() { super.onStop(); - requestDrawOverLays(); } @Override protected void onDestroy() { super.onDestroy(); - if (mFloatingView != null && mFloatingView.isShown()) { - mFloatingView.dismiss(); - } exitRoom(); } @@ -208,9 +236,6 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli @Override protected void onResume() { super.onResume(); - if (mFloatingView != null && mFloatingView.isShown()) { - mFloatingView.dismiss(); - } } @Override @@ -232,58 +257,21 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli switchCamera(); } else if (id == getId("btn_audio_route", "id")) { audioRoute(); - } else if (id == getId("iv_return", "id")) { - floatViewClick(); } } - private void floatViewClick() { - Intent intent = new Intent(this, VideoCallingActivity.class); - if (intent != null) { - intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - } - try { - startActivity(intent); - } catch (Exception e) { - e.printStackTrace(); - } - } private void muteVideo() { boolean isSelected = mButtonMuteVideo.isSelected(); if (!isSelected) { mButtonMuteVideo.setImageDrawable(getDrawable(getId("view_open", "mipmap"))); - closeRemoteVideoViews(); } else { mButtonMuteVideo.setImageDrawable(getDrawable(getId("view_close", "mipmap"))); - refreshRemoteVideoViews(); } + Events.fireEvent("subview.always.hide",(extra)->extra.putBoolean("alwaysHide",!isSelected)); mButtonMuteVideo.setSelected(!isSelected); } - - private void closeRemoteVideoViews() { - for (int i = 0; i < mRemoteViewList.size(); i++) { - if (i < mRemoteUidList.size()) { - mRemoteViewList.get(i).setVisibility(View.INVISIBLE); - } else { - mRemoteViewList.get(i).setVisibility(View.GONE); - } - } - } - - private void refreshRemoteVideoViews() { - for (int i = 0; i < mRemoteViewList.size(); i++) { - if (i < mRemoteUidList.size()) { - String remoteUid = mRemoteUidList.get(i); - mRemoteViewList.get(i).setVisibility(View.VISIBLE); - } else { - mRemoteViewList.get(i).setVisibility(View.GONE); - } - } - } - private void muteAudio() { boolean isSelected = mButtonMuteAudio.isSelected(); if (!isSelected) { @@ -298,6 +286,7 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli private void switchCamera() { mIsFrontCamera = !mIsFrontCamera; + localUserInfo.setFrontCamera(mIsFrontCamera); mTXDeviceManager.switchCamera(mIsFrontCamera); } @@ -313,6 +302,17 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli } } + private void refreshRemoteVideoViews() { + for (int i = 0; i < mRemoteViewList.size(); i++) { + if (i < mUserList.size()) { + UserInfo user = mUserList.get(i); + mRemoteViewList.get(i).changeUser(mTRTCCloud,user); + } else { + mRemoteViewList.get(i).changeUser(mTRTCCloud,null); + } + } + } + private class TRTCCloudImplListener extends TRTCCloudListener { private WeakReference mContext; @@ -325,19 +325,20 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli @Override public void onUserVideoAvailable(String userId, boolean available) { Log.d(TAG, "onUserVideoAvailable userId " + userId + ", mUserCount " + mUserCount + ",available " + available); - int index = mRemoteUidList.indexOf(userId); + UserInfo info = new UserInfo().setPersonid(userId); + int index = mUserList.indexOf(info); if (available) { if (index != -1) { return; } - mRemoteUidList.add(userId); + mUserList.add(info); refreshRemoteVideoViews(); } else { if (index == -1) { return; } mTRTCCloud.stopRemoteView(userId); - mRemoteUidList.remove(index); + mUserList.remove(index); refreshRemoteVideoViews(); } @@ -345,12 +346,11 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli private void refreshRemoteVideoViews() { for (int i = 0; i < mRemoteViewList.size(); i++) { - if (i < mRemoteUidList.size()) { - String remoteUid = mRemoteUidList.get(i); - mRemoteViewList.get(i).setVisibility(View.VISIBLE); - mTRTCCloud.startRemoteView(remoteUid, TRTCCloudDef.TRTC_VIDEO_STREAM_TYPE_SMALL, mRemoteViewList.get(i)); + if (i < mUserList.size()) { + UserInfo user = mUserList.get(i); + mRemoteViewList.get(i).changeUser(mTRTCCloud,user); } else { - mRemoteViewList.get(i).setVisibility(View.GONE); + mRemoteViewList.get(i).changeUser(mTRTCCloud,null); } } } @@ -377,21 +377,4 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli } - public void requestDrawOverLays() { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N && !Settings.canDrawOverlays(VideoCallingActivity.this)) { - Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + VideoCallingActivity.this.getPackageName())); - startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE); - } else { - showFloatingView(); - } - } - - private void showFloatingView() { - if (mFloatingView != null && !mFloatingView.isShown()) { - if ((null != mTRTCCloud)) { - mFloatingView.show(); - mFloatingView.setOnPopupItemClickListener(this); - } - } - } } diff --git a/src/android/res/layout/custom_video_view_layout.xml b/src/android/res/layout/custom_video_view_layout.xml new file mode 100644 index 0000000..a54c6f4 --- /dev/null +++ b/src/android/res/layout/custom_video_view_layout.xml @@ -0,0 +1,24 @@ + + + + + + \ No newline at end of file diff --git a/src/android/res/layout/videocall_activity_calling.xml b/src/android/res/layout/videocall_activity_calling.xml index d921b0b..7059603 100644 --- a/src/android/res/layout/videocall_activity_calling.xml +++ b/src/android/res/layout/videocall_activity_calling.xml @@ -5,11 +5,11 @@ android:background="@color/rl_main_bg"> - + - + - + - + - + - + - + - - - - \ No newline at end of file diff --git a/src/android/res/layout/videocall_view_floating_default.xml b/src/android/res/layout/videocall_view_floating_default.xml deleted file mode 100644 index d97171d..0000000 --- a/src/android/res/layout/videocall_view_floating_default.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file