添加项目
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,50 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'org.jetbrains.kotlin.android'
|
||||
|
||||
android {
|
||||
compileSdk rootProject.ext.compileSdkVersion
|
||||
|
||||
defaultConfig {
|
||||
minSdk rootProject.ext.minSdkVersion
|
||||
targetSdk rootProject.ext.targetSdkVersion
|
||||
versionCode rootProject.ext.versionCode
|
||||
versionName rootProject.ext.versionName
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api fileTree(dir: 'libs', include: ['*.jar'])
|
||||
api 'androidx.appcompat:appcompat:1.0.0'
|
||||
api 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
api 'com.github.bumptech.glide:glide:4.12.0'
|
||||
implementation 'androidx.core:core-ktx:1.8.0'
|
||||
|
||||
def projects = this.rootProject.getAllprojects().stream().map { project -> project.name }.collect()
|
||||
println "all projects : {$projects}"
|
||||
if (projects.contains("tuicore")) {
|
||||
api project(':system:tuicore')
|
||||
} else {
|
||||
api "com.tencent.imsdk:imsdk-plus:7.3.4358"
|
||||
api "com.tencent.liteav.tuikit:tuicore:1.1.18"
|
||||
}
|
||||
|
||||
if (projects.contains("tuicallengine")) {
|
||||
api project(':tuicallengine')
|
||||
} else {
|
||||
api "com.google.code.gson:gson:2.9.1"
|
||||
api "com.tencent.liteav:LiteAVSDK_TRTC:11.4.0.13189"
|
||||
api 'com.tencent.liteav.tuikit:tuicallengine:1.9.0.680'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.tencent.qcloud.tuikit.tuicallkit">
|
||||
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<uses-feature android:name="android.hardware.camera" />
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
|
||||
<!-- Support Android S(31) Bluetooth-->
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
<application>
|
||||
<activity
|
||||
android:name="com.tencent.qcloud.tuikit.tuicallkit.base.BaseCallActivity"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/Theme.AppCompat.NoActionBar" />
|
||||
|
||||
<provider
|
||||
android:name="com.tencent.qcloud.tuikit.tuicallkit.internal.ServiceInitializer"
|
||||
android:authorities="${applicationId}.ServiceInitializer"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
|
||||
<service
|
||||
android:name="com.tencent.qcloud.tuikit.tuicallkit.service.TUICallService"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
|
||||
<service
|
||||
android:name="com.tencent.qcloud.tuikit.tuicallkit.view.floatwindow.FloatWindowService"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.tencent.qcloud.tuikit.TUICommonDefine;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallDefine;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class TUICallKit {
|
||||
|
||||
public static TUICallKit createInstance(Context context) {
|
||||
return TUICallKitImpl.createInstance(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user profile
|
||||
*
|
||||
* @param nickname User name, which can contain up to 500 bytes
|
||||
* @param avatar User profile photo URL, which can contain up to 500 bytes
|
||||
* For example: https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar1.png
|
||||
* @param callback Set the result callback
|
||||
*/
|
||||
public void setSelfInfo(String nickname, String avatar, TUICommonDefine.Callback callback) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a call
|
||||
*
|
||||
* @param userId callees
|
||||
* @param callMediaType Call type
|
||||
*/
|
||||
public void call(String userId, TUICallDefine.MediaType callMediaType) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a call
|
||||
*
|
||||
* @param userId callees
|
||||
* @param callMediaType Call type
|
||||
* @param params Extension param: eg: offlinePushInfo
|
||||
*/
|
||||
public void call(String userId, TUICallDefine.MediaType callMediaType,
|
||||
TUICallDefine.CallParams params, TUICommonDefine.Callback callback) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a group call
|
||||
*
|
||||
* @param groupId GroupId
|
||||
* @param userIdList List of userId
|
||||
* @param callMediaType Call type
|
||||
*/
|
||||
public void groupCall(String groupId, List<String> userIdList, TUICallDefine.MediaType callMediaType) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a group call
|
||||
*
|
||||
* @param groupId GroupId
|
||||
* @param userIdList List of userId
|
||||
* @param callMediaType Call type
|
||||
* @param params Extension param: eg: offlinePushInfo
|
||||
*/
|
||||
public void groupCall(String groupId, List<String> userIdList,
|
||||
TUICallDefine.MediaType callMediaType, TUICallDefine.CallParams params,
|
||||
TUICommonDefine.Callback callback) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Join a current call
|
||||
*
|
||||
* @param roomId current call room ID
|
||||
* @param callMediaType call type
|
||||
*/
|
||||
public void joinInGroupCall(TUICommonDefine.RoomId roomId, String groupId, TUICallDefine.MediaType callMediaType) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ringtone (preferably shorter than 30s)
|
||||
*
|
||||
* @param filePath Callee ringtone path
|
||||
*/
|
||||
public void setCallingBell(String filePath) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the mute mode (the callee doesn't ring)
|
||||
*/
|
||||
public void enableMuteMode(boolean enable) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the floating window
|
||||
*/
|
||||
public void enableFloatWindow(boolean enable) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,846 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.tencent.liteav.beauty.TXBeautyManager;
|
||||
import com.tencent.qcloud.tuicore.TUIConstants;
|
||||
import com.tencent.qcloud.tuicore.TUICore;
|
||||
import com.tencent.qcloud.tuicore.TUILogin;
|
||||
import com.tencent.qcloud.tuicore.interfaces.ITUINotification;
|
||||
import com.tencent.qcloud.tuicore.interfaces.TUICallback;
|
||||
import com.tencent.qcloud.tuicore.util.SPUtils;
|
||||
import com.tencent.qcloud.tuicore.util.ToastUtil;
|
||||
import com.tencent.qcloud.tuikit.TUICommonDefine;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallDefine;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallDefine.Scene;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallDefine.Status;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallEngine;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallObserver;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.impl.base.TUILog;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.utils.PermissionUtils;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.CallingUserModel;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.Constants;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.TUICallingStatusManager;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.config.OfflinePushInfoConfig;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.event.CallBackEvent;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.extensions.CallingBellFeature;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.extensions.CallingKeepAliveFeature;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.extensions.CallingScreenSensorFeature;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.utils.DeviceUtils;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.utils.PermissionRequest;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.utils.UserInfoUtils;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.TUICallingViewManager;
|
||||
import com.tencent.trtc.TRTCCloud;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
public final class TUICallKitImpl extends TUICallKit implements ITUINotification {
|
||||
private static final String TAG = "TUICallKit";
|
||||
|
||||
private static TUICallKitImpl sInstance;
|
||||
private final Context mContext;
|
||||
private final UserInfoUtils mUserInfoUtils;
|
||||
|
||||
private final CallingKeepAliveFeature mCallingKeepAliveFeature;
|
||||
private final CallingScreenSensorFeature mCallingScreenSensorFeature;
|
||||
private final CallingBellFeature mCallingBellFeature;
|
||||
private final TUICallingViewManager mCallingViewManager;
|
||||
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
private Runnable mTimeRunnable;
|
||||
private int mTimeCount;
|
||||
private Handler mTimeHandler;
|
||||
private HandlerThread mTimeHandlerThread;
|
||||
|
||||
private long mSelfLowQualityTime;
|
||||
private long mOtherUserLowQualityTime;
|
||||
|
||||
private List<CallingUserModel> mInviteeList = new ArrayList<>();
|
||||
private CallingUserModel mInviter = new CallingUserModel();
|
||||
|
||||
public static TUICallKitImpl createInstance(Context context) {
|
||||
if (null == sInstance) {
|
||||
synchronized (TUICallKitImpl.class) {
|
||||
if (null == sInstance) {
|
||||
sInstance = new TUICallKitImpl(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private TUICallKitImpl(Context context) {
|
||||
mContext = context.getApplicationContext();
|
||||
TUICallEngine.createInstance(mContext).addObserver(mTUICallObserver);
|
||||
mCallingKeepAliveFeature = new CallingKeepAliveFeature(mContext);
|
||||
mCallingScreenSensorFeature = new CallingScreenSensorFeature(mContext);
|
||||
mCallingBellFeature = new CallingBellFeature(mContext);
|
||||
mCallingViewManager = new TUICallingViewManager(mContext);
|
||||
mUserInfoUtils = new UserInfoUtils();
|
||||
createTimeHandler();
|
||||
registerCallingEvent();
|
||||
}
|
||||
|
||||
private void registerCallingEvent() {
|
||||
//Login Event
|
||||
TUICore.registerEvent(TUIConstants.TUILogin.EVENT_LOGIN_STATE_CHANGED,
|
||||
TUIConstants.TUILogin.EVENT_SUB_KEY_USER_LOGIN_SUCCESS, this);
|
||||
TUICore.registerEvent(TUIConstants.TUILogin.EVENT_LOGIN_STATE_CHANGED,
|
||||
TUIConstants.TUILogin.EVENT_SUB_KEY_USER_LOGOUT_SUCCESS, this);
|
||||
|
||||
//TUICallkit Event
|
||||
TUICore.registerEvent(Constants.EVENT_TUICALLING_CHANGED, Constants.EVENT_SUB_CALL_STATUS_CHANGED, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelfInfo(String nickname, String avatar, TUICommonDefine.Callback callback) {
|
||||
TUICallEngine.createInstance(mContext).setSelfInfo(nickname, avatar, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(String userId, TUICallDefine.MediaType callMediaType) {
|
||||
TUICallDefine.CallParams params = new TUICallDefine.CallParams();
|
||||
params.offlinePushInfo = OfflinePushInfoConfig.createOfflinePushInfo(mContext);
|
||||
params.timeout = Constants.SIGNALING_MAX_TIME;
|
||||
call(userId, callMediaType, params, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(String userId, TUICallDefine.MediaType callMediaType, TUICallDefine.CallParams params,
|
||||
TUICommonDefine.Callback callback) {
|
||||
if (TextUtils.isEmpty(userId)) {
|
||||
TUILog.e(TAG, "call failed, userId is empty");
|
||||
callbackError(callback, TUICallDefine.ERROR_PARAM_INVALID, "call failed, userId is empty");
|
||||
return;
|
||||
}
|
||||
if (TUICallDefine.MediaType.Unknown.equals(callMediaType)) {
|
||||
TUILog.e(TAG, "call failed, callMediaType is Unknown");
|
||||
callbackError(callback, TUICallDefine.ERROR_PARAM_INVALID, "call failed, callMediaType is Unknown");
|
||||
return;
|
||||
}
|
||||
|
||||
checkCallingPermission(callMediaType, new TUICallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
|
||||
TUICallEngine.createInstance(mContext).call(userId, callMediaType, params,
|
||||
new TUICommonDefine.Callback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
CallingUserModel model = new CallingUserModel();
|
||||
model.userId = userId;
|
||||
mInviteeList.add(model);
|
||||
TUICallingStatusManager.sharedInstance(mContext).setMediaType(callMediaType);
|
||||
TUICallingStatusManager.sharedInstance(mContext).setCallRole(TUICallDefine.Role.Caller);
|
||||
TUICallingStatusManager.sharedInstance(mContext).setCallScene(Scene.SINGLE_CALL);
|
||||
|
||||
showCallingView();
|
||||
mCallingBellFeature.startDialingMusic();
|
||||
callbackSuccess(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errCode, String errMsg) {
|
||||
if (errCode == TUICallDefine.ERROR_PACKAGE_NOT_PURCHASED) {
|
||||
errMsg = mContext.getString(R.string.tuicalling_package_not_purchased);
|
||||
}
|
||||
ToastUtil.toastLongMessage(errMsg);
|
||||
callbackError(callback, errCode, errMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errorCode, String errorMessage) {
|
||||
callbackError(callback, errorCode, errorMessage);
|
||||
resetCall();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void groupCall(String groupId, List<String> userIdList, TUICallDefine.MediaType callMediaType) {
|
||||
TUICallDefine.CallParams params = new TUICallDefine.CallParams();
|
||||
params.offlinePushInfo = OfflinePushInfoConfig.createOfflinePushInfo(mContext);
|
||||
params.timeout = Constants.SIGNALING_MAX_TIME;
|
||||
groupCall(groupId, userIdList, callMediaType, params, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void groupCall(String groupId, List<String> userIdList, TUICallDefine.MediaType callMediaType,
|
||||
TUICallDefine.CallParams params, TUICommonDefine.Callback callback) {
|
||||
if (TextUtils.isEmpty(groupId)) {
|
||||
TUILog.e(TAG, "groupCall failed, groupId is empty");
|
||||
callbackError(callback, TUICallDefine.ERROR_PARAM_INVALID, "groupCall failed, groupId is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
if (TUICallDefine.MediaType.Unknown.equals(callMediaType)) {
|
||||
TUILog.e(TAG, "groupCall failed, callMediaType is Unknown");
|
||||
callbackError(callback, TUICallDefine.ERROR_PARAM_INVALID, "groupCall failed, callMediaType is Unknown");
|
||||
return;
|
||||
}
|
||||
|
||||
if (userIdList == null || userIdList.isEmpty()) {
|
||||
TUILog.e(TAG, "groupCall failed, userIdList is empty");
|
||||
callbackError(callback, TUICallDefine.ERROR_PARAM_INVALID, "groupCall failed, userIdList is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
if (userIdList.size() >= Constants.MAX_USER) {
|
||||
ToastUtil.toastLongMessage(mContext.getString(R.string.tuicalling_user_exceed_limit));
|
||||
TUILog.e(TAG, "groupCall failed, exceeding max user number: 9");
|
||||
callbackError(callback, TUICallDefine.ERROR_PARAM_INVALID, "groupCall failed, exceeding max user number");
|
||||
return;
|
||||
}
|
||||
|
||||
checkCallingPermission(callMediaType, new TUICallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
TUICallEngine.createInstance(mContext).groupCall(groupId, userIdList, callMediaType,
|
||||
params, new TUICommonDefine.Callback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
for (String userId : userIdList) {
|
||||
if (!TextUtils.isEmpty(userId)) {
|
||||
CallingUserModel model = new CallingUserModel();
|
||||
model.userId = userId;
|
||||
mInviteeList.add(model);
|
||||
}
|
||||
}
|
||||
TUICallingStatusManager.sharedInstance(mContext).setMediaType(callMediaType);
|
||||
TUICallingStatusManager.sharedInstance(mContext).setCallRole(TUICallDefine.Role.Caller);
|
||||
TUICallingStatusManager.sharedInstance(mContext).setCallScene(Scene.GROUP_CALL);
|
||||
TUICallingStatusManager.sharedInstance(mContext).setGroupId(groupId);
|
||||
|
||||
showCallingView();
|
||||
mCallingBellFeature.startDialingMusic();
|
||||
callbackSuccess(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errCode, String errMsg) {
|
||||
if (errCode == TUICallDefine.ERROR_PACKAGE_NOT_SUPPORTED) {
|
||||
errMsg = mContext.getString(R.string.tuicalling_package_not_support);
|
||||
}
|
||||
ToastUtil.toastLongMessage(errMsg);
|
||||
callbackError(callback, errCode, errMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errorCode, String errorMessage) {
|
||||
callbackError(callback, errorCode, errorMessage);
|
||||
resetCall();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showCallingView() {
|
||||
mCallingViewManager.createCallingView(mInviteeList, mInviter);
|
||||
TUICallingStatusManager.sharedInstance(mContext).updateCallStatus(TUICallDefine.Status.Waiting);
|
||||
queryUserInfo();
|
||||
|
||||
mCallingKeepAliveFeature.startKeepAlive();
|
||||
mCallingScreenSensorFeature.registerSensorEventListener();
|
||||
|
||||
mCallingViewManager.showCallingView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void joinInGroupCall(TUICommonDefine.RoomId roomId, String groupId, TUICallDefine.MediaType mediaType) {
|
||||
int intRoomId = (roomId != null) ? roomId.intRoomId : 0;
|
||||
if (intRoomId <= 0 || intRoomId >= Constants.ROOM_ID_MAX) {
|
||||
TUILog.e(TAG, "joinInGroupCall failed, roomId is invalid");
|
||||
return;
|
||||
}
|
||||
if (TextUtils.isEmpty(groupId)) {
|
||||
TUILog.e(TAG, "joinInGroupCall failed, groupId is empty");
|
||||
return;
|
||||
}
|
||||
if (TUICallDefine.MediaType.Unknown.equals(mediaType)) {
|
||||
TUILog.e(TAG, "joinInGroupCall failed, mediaType is unknown");
|
||||
return;
|
||||
}
|
||||
|
||||
checkCallingPermission(mediaType, new TUICallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
TUICallEngine.createInstance(mContext).joinInGroupCall(roomId, groupId, mediaType,
|
||||
new TUICommonDefine.Callback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
TUICallingStatusManager.sharedInstance(mContext).updateCallStatus(Status.Accept);
|
||||
TUICallingStatusManager.sharedInstance(mContext).setMediaType(mediaType);
|
||||
TUICallingStatusManager.sharedInstance(mContext).setCallScene(Scene.GROUP_CALL);
|
||||
TUICallingStatusManager.sharedInstance(mContext).setCallRole(TUICallDefine.Role.Called);
|
||||
TUICallingStatusManager.sharedInstance(mContext).setGroupId(groupId);
|
||||
|
||||
mCallingViewManager.createGroupCallingAcceptView();
|
||||
mCallingViewManager.showCallingView();
|
||||
showTimeCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errCode, String errMsg) {
|
||||
if (errCode == TUICallDefine.ERROR_PACKAGE_NOT_SUPPORTED) {
|
||||
errMsg = mContext.getString(R.string.tuicalling_package_not_support);
|
||||
}
|
||||
ToastUtil.toastLongMessage(errMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errorCode, String errorMessage) {
|
||||
resetCall();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallingBell(String filePath) {
|
||||
SPUtils.getInstance(CallingBellFeature.PROFILE_TUICALLING).put(CallingBellFeature.PROFILE_CALL_BELL, filePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableMuteMode(boolean enable) {
|
||||
SPUtils.getInstance(CallingBellFeature.PROFILE_TUICALLING).put(CallingBellFeature.PROFILE_MUTE_MODE, enable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableFloatWindow(boolean enable) {
|
||||
mCallingViewManager.enableFloatWindow(enable);
|
||||
}
|
||||
|
||||
public void queryOfflineCall() {
|
||||
if (Status.None.equals(TUICallingStatusManager.sharedInstance(mContext).getCallStatus())) {
|
||||
TUICallEngine.createInstance(mContext).queryOfflineCall();
|
||||
}
|
||||
}
|
||||
|
||||
private final TUICallObserver mTUICallObserver = new TUICallObserver() {
|
||||
@Override
|
||||
public void onError(int code, String msg) {
|
||||
super.onError(code, msg);
|
||||
ToastUtil.toastLongMessage(mContext.getString(R.string.tuicalling_toast_call_error_msg, code, msg));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCallReceived(String callerId, List<String> calleeIdList, String groupId,
|
||||
TUICallDefine.MediaType callMediaType, String userData) {
|
||||
super.onCallReceived(callerId, calleeIdList, groupId, callMediaType, userData);
|
||||
|
||||
if (TUICallDefine.MediaType.Unknown.equals(callMediaType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (calleeIdList == null || calleeIdList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (calleeIdList.size() >= Constants.MAX_USER) {
|
||||
ToastUtil.toastLongMessage(mContext.getString(R.string.tuicalling_user_exceed_limit));
|
||||
return;
|
||||
}
|
||||
|
||||
//when app comes back to foreground, start the call
|
||||
if (!DeviceUtils.isAppRunningForeground(mContext) && !PermissionUtils.hasPermission(mContext)) {
|
||||
TUILog.w(TAG, "App is in background");
|
||||
mCallingBellFeature.startRing();
|
||||
return;
|
||||
}
|
||||
|
||||
checkCallingPermission(callMediaType, new TUICallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
for (String userId : calleeIdList) {
|
||||
if (!TextUtils.isEmpty(userId)) {
|
||||
CallingUserModel model = new CallingUserModel();
|
||||
model.userId = userId;
|
||||
mInviteeList.add(model);
|
||||
}
|
||||
}
|
||||
|
||||
mInviter.userId = callerId;
|
||||
Scene scene;
|
||||
if (!TextUtils.isEmpty(groupId)) {
|
||||
scene = Scene.GROUP_CALL;
|
||||
} else {
|
||||
scene = (calleeIdList.size() > 1) ? Scene.MULTI_CALL : Scene.SINGLE_CALL;
|
||||
}
|
||||
TUICallingStatusManager.sharedInstance(mContext).setMediaType(callMediaType);
|
||||
TUICallingStatusManager.sharedInstance(mContext).setCallRole(TUICallDefine.Role.Called);
|
||||
TUICallingStatusManager.sharedInstance(mContext).setCallScene(scene);
|
||||
TUICallingStatusManager.sharedInstance(mContext).setGroupId(groupId);
|
||||
|
||||
showCallingView();
|
||||
mCallingBellFeature.startRing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errorCode, String errorMessage) {
|
||||
TUICallEngine.createInstance(mContext).reject(null);
|
||||
resetCall();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCallCancelled(String callerId) {
|
||||
super.onCallCancelled(callerId);
|
||||
EventBus.getDefault().post(new CallBackEvent(CallBackEvent.CALL_CANCEL));
|
||||
resetCall();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCallBegin(TUICommonDefine.RoomId roomId, TUICallDefine.MediaType callMediaType,
|
||||
TUICallDefine.Role callRole) {
|
||||
super.onCallBegin(roomId, callMediaType, callRole);
|
||||
mCallingBellFeature.stopMusic();
|
||||
TUICallingStatusManager.sharedInstance(mContext).updateCallStatus(TUICallDefine.Status.Accept);
|
||||
showTimeCount();
|
||||
EventBus.getDefault().post(new CallBackEvent(CallBackEvent.CALL_BEGIN));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCallEnd(TUICommonDefine.RoomId roomId, TUICallDefine.MediaType callMediaType,
|
||||
TUICallDefine.Role callRole, long totalTime) {
|
||||
super.onCallEnd(roomId, callMediaType, callRole, totalTime);
|
||||
resetCall();
|
||||
EventBus.getDefault().post(new CallBackEvent(CallBackEvent.CALL_END));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCallMediaTypeChanged(TUICallDefine.MediaType oldCallMediaType,
|
||||
TUICallDefine.MediaType newCallMediaType) {
|
||||
super.onCallMediaTypeChanged(oldCallMediaType, newCallMediaType);
|
||||
if (!oldCallMediaType.equals(newCallMediaType)) {
|
||||
TUICallingStatusManager.sharedInstance(mContext).setMediaType(newCallMediaType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserReject(String userId) {
|
||||
super.onUserReject(userId);
|
||||
CallingUserModel userModel = findCallingUserModel(userId);
|
||||
mCallingViewManager.userLeave(userModel);
|
||||
showUserToast(userModel, R.string.tuicalling_toast_user_reject_call);
|
||||
mInviteeList.remove(userModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserNoResponse(String userId) {
|
||||
super.onUserNoResponse(userId);
|
||||
CallingUserModel userModel = findCallingUserModel(userId);
|
||||
mCallingViewManager.userLeave(userModel);
|
||||
showUserToast(userModel, R.string.tuicalling_toast_user_not_response);
|
||||
mInviteeList.remove(userModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserLineBusy(String userId) {
|
||||
super.onUserLineBusy(userId);
|
||||
CallingUserModel userModel = findCallingUserModel(userId);
|
||||
mCallingViewManager.userLeave(userModel);
|
||||
showUserToast(userModel, R.string.tuicalling_toast_user_busy);
|
||||
mInviteeList.remove(userModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserJoin(String userId) {
|
||||
super.onUserJoin(userId);
|
||||
CallingUserModel userModel = findCallingUserModel(userId);
|
||||
if (userModel == null) {
|
||||
userModel = new CallingUserModel();
|
||||
userModel.userId = userId;
|
||||
}
|
||||
mCallingViewManager.userEnter(userModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserLeave(String userId) {
|
||||
super.onUserLeave(userId);
|
||||
CallingUserModel userModel = findCallingUserModel(userId);
|
||||
mCallingViewManager.userLeave(userModel);
|
||||
showUserToast(userModel, R.string.tuicalling_toast_user_end);
|
||||
mInviteeList.remove(userModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserVideoAvailable(String userId, boolean isVideoAvailable) {
|
||||
super.onUserVideoAvailable(userId, isVideoAvailable);
|
||||
CallingUserModel model = findCallingUserModel(userId);
|
||||
if (model != null && model.isVideoAvailable != isVideoAvailable) {
|
||||
model.isVideoAvailable = isVideoAvailable;
|
||||
mCallingViewManager.updateUser(model);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserAudioAvailable(String userId, boolean isAudioAvailable) {
|
||||
super.onUserAudioAvailable(userId, isAudioAvailable);
|
||||
CallingUserModel model = findCallingUserModel(userId);
|
||||
if (model != null && model.isAudioAvailable != isAudioAvailable) {
|
||||
model.isAudioAvailable = isAudioAvailable;
|
||||
mCallingViewManager.updateUser(model);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserVoiceVolumeChanged(Map<String, Integer> volumeMap) {
|
||||
super.onUserVoiceVolumeChanged(volumeMap);
|
||||
if (Scene.SINGLE_CALL.equals(TUICallingStatusManager.sharedInstance(mContext).getCallScene())) {
|
||||
return;
|
||||
}
|
||||
for (Map.Entry<String, Integer> entry : volumeMap.entrySet()) {
|
||||
if (null != entry && !TextUtils.isEmpty(entry.getKey())) {
|
||||
CallingUserModel userModel = findCallingUserModel(entry.getKey());
|
||||
if (userModel != null && userModel.volume != entry.getValue()) {
|
||||
userModel.volume = entry.getValue();
|
||||
mCallingViewManager.updateUser(userModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserNetworkQualityChanged(List<TUICommonDefine.NetworkQualityInfo> networkQualityList) {
|
||||
super.onUserNetworkQualityChanged(networkQualityList);
|
||||
updateNetworkQuality(networkQualityList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onKickedOffline() {
|
||||
super.onKickedOffline();
|
||||
TUICallEngine.createInstance(mContext).hangup(null);
|
||||
resetCall();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserSigExpired() {
|
||||
super.onUserSigExpired();
|
||||
TUICallEngine.createInstance(mContext).hangup(null);
|
||||
resetCall();
|
||||
}
|
||||
};
|
||||
|
||||
private void resetCall() {
|
||||
runOnMainThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
stopTimeCount();
|
||||
mCallingBellFeature.stopMusic();
|
||||
mCallingKeepAliveFeature.stopKeepAlive();
|
||||
mCallingScreenSensorFeature.unregisterSensorEventListener();
|
||||
|
||||
mCallingViewManager.closeCallingView();
|
||||
mInviter = new CallingUserModel();
|
||||
mInviteeList.clear();
|
||||
TUICallingStatusManager.sharedInstance(mContext).clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void runOnMainThread(Runnable task) {
|
||||
if (null != task) {
|
||||
mMainHandler.post(task);
|
||||
}
|
||||
}
|
||||
|
||||
private void queryUserInfo() {
|
||||
ArrayList<CallingUserModel> list = new ArrayList<>();
|
||||
list.add(mInviter);
|
||||
list.addAll(mInviteeList);
|
||||
mUserInfoUtils.getUserInfo(list, new UserInfoUtils.UserCallback() {
|
||||
@Override
|
||||
public void onSuccess(List<CallingUserModel> list) {
|
||||
if (null == list || list.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (CallingUserModel model : list) {
|
||||
if (null != model && !TextUtils.isEmpty(model.userId)) {
|
||||
CallingUserModel userModel = findCallingUserModel(model.userId);
|
||||
if (null != userModel) {
|
||||
userModel.userName = model.userName;
|
||||
userModel.userAvatar = model.userAvatar;
|
||||
}
|
||||
}
|
||||
}
|
||||
mCallingViewManager.updateCallingUserView(mInviteeList, mInviter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed(int errorCode, String errorMsg) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showUserToast(CallingUserModel model, int msgId) {
|
||||
if (null == model || TextUtils.isEmpty(model.userId)) {
|
||||
return;
|
||||
}
|
||||
if (!TextUtils.isEmpty(model.userName)) {
|
||||
ToastUtil.toastLongMessage(mContext.getString(msgId, model.userName));
|
||||
return;
|
||||
}
|
||||
UserInfoUtils userInfoUtils = new UserInfoUtils();
|
||||
userInfoUtils.getUserInfo(model.userId, new UserInfoUtils.UserCallback() {
|
||||
@Override
|
||||
public void onSuccess(List<CallingUserModel> list) {
|
||||
if (null == list || list.isEmpty() || null == list.get(0) || TextUtils.isEmpty(list.get(0).userId)) {
|
||||
ToastUtil.toastLongMessage(mContext.getString(msgId, model.userId));
|
||||
return;
|
||||
}
|
||||
|
||||
model.userName = list.get(0).userName;
|
||||
model.userAvatar = list.get(0).userAvatar;
|
||||
ToastUtil.toastLongMessage(mContext.getString(msgId, model.userName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed(int errorCode, String errorMsg) {
|
||||
ToastUtil.toastLongMessage(mContext.getString(msgId, model.userId));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private CallingUserModel findCallingUserModel(String userId) {
|
||||
if (TextUtils.isEmpty(userId)) {
|
||||
return null;
|
||||
}
|
||||
if (userId.equals(mInviter.userId)) {
|
||||
return mInviter;
|
||||
} else {
|
||||
for (CallingUserModel model : mInviteeList) {
|
||||
if (null != model && !TextUtils.isEmpty(model.userId) && userId.equals(model.userId)) {
|
||||
return model;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void createTimeHandler() {
|
||||
mTimeHandlerThread = new HandlerThread("time-count-thread");
|
||||
mTimeHandlerThread.start();
|
||||
mTimeHandler = new Handler(mTimeHandlerThread.getLooper());
|
||||
}
|
||||
|
||||
private void showTimeCount() {
|
||||
if (mTimeRunnable != null) {
|
||||
return;
|
||||
}
|
||||
mTimeCount = 0;
|
||||
mTimeRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mTimeCount++;
|
||||
mCallingViewManager.userCallingTimeStr(getShowTime(mTimeCount));
|
||||
mTimeHandler.postDelayed(mTimeRunnable, 1000);
|
||||
}
|
||||
};
|
||||
mTimeHandler.post(mTimeRunnable);
|
||||
}
|
||||
|
||||
private String getShowTime(int count) {
|
||||
return mContext.getString(R.string.tuicalling_called_time_format, count / 60, count % 60);
|
||||
}
|
||||
|
||||
private void stopTimeCount() {
|
||||
mTimeHandler.removeCallbacks(mTimeRunnable);
|
||||
mTimeRunnable = null;
|
||||
mTimeCount = 0;
|
||||
}
|
||||
|
||||
private void updateNetworkQuality(List<TUICommonDefine.NetworkQualityInfo> networkQualityList) {
|
||||
if (networkQualityList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
TUICommonDefine.NetworkQualityInfo localInfo = null;
|
||||
Iterator<TUICommonDefine.NetworkQualityInfo> iterator = networkQualityList.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
TUICommonDefine.NetworkQualityInfo tempInfo = iterator.next();
|
||||
if (TUILogin.getLoginUser().equals(tempInfo.userId)) {
|
||||
localInfo = tempInfo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
boolean isLocalLowQuality = false;
|
||||
if (localInfo != null) {
|
||||
isLocalLowQuality = isLowQuality(localInfo.quality);
|
||||
}
|
||||
if (isLocalLowQuality) {
|
||||
updateLowQualityTip(true);
|
||||
} else if (iterator.hasNext()) {
|
||||
TUICommonDefine.NetworkQualityInfo remoteInfo = iterator.next();
|
||||
if (isLowQuality(remoteInfo.quality)) {
|
||||
updateLowQualityTip(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isLowQuality(TUICommonDefine.NetworkQuality quality) {
|
||||
if (null == quality) {
|
||||
return false;
|
||||
}
|
||||
boolean lowQuality;
|
||||
switch (quality) {
|
||||
case Vbad:
|
||||
case Down:
|
||||
lowQuality = true;
|
||||
break;
|
||||
default:
|
||||
lowQuality = false;
|
||||
}
|
||||
return lowQuality;
|
||||
}
|
||||
|
||||
private void updateLowQualityTip(boolean isSelf) {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
if (isSelf) {
|
||||
if (currentTime - mSelfLowQualityTime > Constants.MIN_DURATION_SHOW_LOW_QUALITY) {
|
||||
ToastUtil.toastShortMessage(mContext.getString(R.string.tuicalling_self_network_low_quality));
|
||||
mSelfLowQualityTime = currentTime;
|
||||
}
|
||||
} else {
|
||||
if (currentTime - mOtherUserLowQualityTime > Constants.MIN_DURATION_SHOW_LOW_QUALITY) {
|
||||
ToastUtil.toastShortMessage(mContext.getString(R.string.tuicalling_other_party_network_low_quality));
|
||||
mOtherUserLowQualityTime = currentTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCallingPermission(TUICallDefine.MediaType mediaType, TUICallback callback) {
|
||||
PermissionRequest.PermissionCallback permissionCallback = new PermissionRequest.PermissionCallback() {
|
||||
@Override
|
||||
public void onGranted() {
|
||||
super.onGranted();
|
||||
if (callback != null) {
|
||||
callback.onSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDialogRefused() {
|
||||
super.onDialogRefused();
|
||||
if (callback != null) {
|
||||
callback.onError(TUICallDefine.ERROR_PERMISSION_DENIED, "permission denied");
|
||||
}
|
||||
}
|
||||
};
|
||||
if (TUICallDefine.MediaType.Video.equals(mediaType)) {
|
||||
PermissionRequest.requestPermission(mContext, PermissionRequest.PERMISSION_MICROPHONE,
|
||||
PermissionRequest.PERMISSION_CAMERA, permissionCallback);
|
||||
} else {
|
||||
PermissionRequest.requestPermission(mContext, PermissionRequest.PERMISSION_MICROPHONE, permissionCallback);
|
||||
}
|
||||
}
|
||||
|
||||
private int generateRoomId() {
|
||||
return new Random().nextInt(Constants.ROOM_ID_MAX - Constants.ROOM_ID_MIN + 1) + Constants.ROOM_ID_MIN;
|
||||
}
|
||||
|
||||
private void initCallEngine() {
|
||||
TUICallEngine.createInstance(mContext).init(TUILogin.getSdkAppId(), TUILogin.getLoginUser(),
|
||||
TUILogin.getUserSig(), new TUICommonDefine.Callback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errCode, String errMsg) {
|
||||
}
|
||||
});
|
||||
initCallVideoParams();
|
||||
initCallBeautyParams();
|
||||
}
|
||||
|
||||
private void initCallVideoParams() {
|
||||
//set video render params of loginUser
|
||||
TUICommonDefine.VideoRenderParams renderParams = new TUICommonDefine.VideoRenderParams();
|
||||
renderParams.fillMode = TUICommonDefine.VideoRenderParams.FillMode.Fill;
|
||||
renderParams.rotation = TUICommonDefine.VideoRenderParams.Rotation.Rotation_0;
|
||||
String user = TUILogin.getLoginUser();
|
||||
TUICallEngine.createInstance(mContext).setVideoRenderParams(user, renderParams, new TUICommonDefine.Callback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errCode, String errMsg) {
|
||||
}
|
||||
});
|
||||
|
||||
//set video encoder params
|
||||
TUICommonDefine.VideoEncoderParams encoderParams = new TUICommonDefine.VideoEncoderParams();
|
||||
encoderParams.resolution = TUICommonDefine.VideoEncoderParams.Resolution.Resolution_640_360;
|
||||
encoderParams.resolutionMode = TUICommonDefine.VideoEncoderParams.ResolutionMode.Portrait;
|
||||
TUICallEngine.createInstance(mContext).setVideoEncoderParams(encoderParams, new TUICommonDefine.Callback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errCode, String errMsg) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initCallBeautyParams() {
|
||||
TRTCCloud trtcCloud = TUICallEngine.createInstance(mContext).getTRTCCloudInstance();
|
||||
TXBeautyManager txBeautyManager = trtcCloud.getBeautyManager();
|
||||
txBeautyManager.setBeautyStyle(TXBeautyManager.TXBeautyStyleNature);
|
||||
txBeautyManager.setBeautyLevel(6);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotifyEvent(String key, String subKey, Map<String, Object> param) {
|
||||
//Login Event
|
||||
if (TUIConstants.TUILogin.EVENT_LOGIN_STATE_CHANGED.equals(key)) {
|
||||
if (TUIConstants.TUILogin.EVENT_SUB_KEY_USER_LOGOUT_SUCCESS.equals(subKey)) {
|
||||
//logout succeed: if user is in the call, end the call first and then clean data
|
||||
TUICallEngine.createInstance(mContext).hangup(null);
|
||||
TUICallEngine.destroyInstance();
|
||||
resetCall();
|
||||
} else if (TUIConstants.TUILogin.EVENT_SUB_KEY_USER_LOGIN_SUCCESS.equals(subKey)) {
|
||||
//login succeed: add "TUICallObserver" again
|
||||
TUICallEngine.createInstance(mContext).addObserver(mTUICallObserver);
|
||||
//login succeed: initialize "TUICallEngine"
|
||||
initCallEngine();
|
||||
}
|
||||
}
|
||||
|
||||
//TUICallkit Event
|
||||
if (Constants.EVENT_TUICALLING_CHANGED.equals(key)
|
||||
&& Constants.EVENT_SUB_CALL_STATUS_CHANGED.equals(subKey) && param != null) {
|
||||
if (TUICallDefine.Status.None.equals(param.get(Constants.CALL_STATUS))) {
|
||||
resetCall();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void callbackSuccess(TUICommonDefine.Callback callback) {
|
||||
if (callback != null) {
|
||||
callback.onSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
public void callbackError(TUICommonDefine.Callback callback, int errCode, String errMsg) {
|
||||
if (callback != null) {
|
||||
callback.onError(errCode, errMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.base;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.R;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.event.CallBackEvent;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.utils.DeviceUtils;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.root.BaseCallView;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
public class BaseCallActivity extends AppCompatActivity {
|
||||
private static AppCompatActivity mActivity;
|
||||
private static BaseCallView mBaseCallView;
|
||||
private static RelativeLayout mLayoutContainer;
|
||||
|
||||
public static void updateBaseView(BaseCallView view) {
|
||||
mBaseCallView = view;
|
||||
if (null != mLayoutContainer && null != mBaseCallView) {
|
||||
mLayoutContainer.removeAllViews();
|
||||
if (null != mBaseCallView.getParent()) {
|
||||
((ViewGroup) mBaseCallView.getParent()).removeView(mBaseCallView);
|
||||
}
|
||||
mLayoutContainer.addView(mBaseCallView);
|
||||
}
|
||||
}
|
||||
|
||||
public static void finishActivity() {
|
||||
if (null != mActivity) {
|
||||
mActivity.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
DeviceUtils.setScreenLockParams(getWindow());
|
||||
mActivity = this;
|
||||
setContentView(R.layout.tuicalling_base_activity);
|
||||
EventBus.getDefault().register(this);
|
||||
initStatusBar();
|
||||
}
|
||||
|
||||
private void initStatusBar() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
Window window = getWindow();
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
||||
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
||||
window.setStatusBarColor(Color.TRANSPARENT);
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
initView();
|
||||
// clear notifications after a call is processed
|
||||
NotificationManager notificationManager =
|
||||
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.cancelAll();
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
mLayoutContainer = findViewById(R.id.rl_container);
|
||||
mLayoutContainer.removeAllViews();
|
||||
if (null != mBaseCallView) {
|
||||
if (null != mBaseCallView.getParent()) {
|
||||
((ViewGroup) mBaseCallView.getParent()).removeView(mBaseCallView);
|
||||
}
|
||||
mLayoutContainer.addView(mBaseCallView);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
EventBus.getDefault().unregister(this);
|
||||
if (null != mBaseCallView && null != mBaseCallView.getParent()) {
|
||||
((ViewGroup) mBaseCallView.getParent()).removeView(mBaseCallView);
|
||||
}
|
||||
mBaseCallView = null;
|
||||
mLayoutContainer = null;
|
||||
mActivity = null;
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEvent(CallBackEvent event) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.base;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class CallingUserModel {
|
||||
public String userId;
|
||||
public String userAvatar;
|
||||
public String userName;
|
||||
public boolean isEnter;
|
||||
public boolean isAudioAvailable;
|
||||
public boolean isVideoAvailable;
|
||||
public int volume;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
CallingUserModel model = (CallingUserModel) o;
|
||||
return Objects.equals(userId, model.userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CallingUserModel{"
|
||||
+ "userId='" + userId
|
||||
+ ", userAvatar='" + userAvatar
|
||||
+ ", userName='" + userName
|
||||
+ ", isEnter=" + isEnter
|
||||
+ ", isAudioAvailable=" + isAudioAvailable
|
||||
+ ", isVideoAvailable=" + isVideoAvailable
|
||||
+ ", volume=" + volume
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.base;
|
||||
|
||||
public class Constants {
|
||||
public static final String TUICALLKIT = "TUICallKit";
|
||||
|
||||
public static final int ROOM_ID_MIN = 1;
|
||||
public static final int ROOM_ID_MAX = Integer.MAX_VALUE;
|
||||
|
||||
//信令超时时长,默认 30s
|
||||
public static int SIGNALING_MAX_TIME = 30;
|
||||
|
||||
public static final int MIN_AUDIO_VOLUME = 10;
|
||||
public static final int MAX_USER = 9;
|
||||
public static final int MIN_DURATION_SHOW_LOW_QUALITY = 5000; //Minimum interval for displaying poor network
|
||||
|
||||
public static final String EVENT_TUICALLING_CHANGED = "eventTUICallingChanged";
|
||||
|
||||
public static final String EVENT_SUB_CALL_STATUS_CHANGED = "eventSubCallStatusChanged";
|
||||
public static final String EVENT_SUB_CALL_TYPE_CHANGED = "eventSubMediaTypeChanged";
|
||||
public static final String EVENT_SUB_CAMERA_OPEN = "eventSubCameraOpen";
|
||||
public static final String EVENT_SUB_CAMERA_FRONT = "eventSubCameraFront";
|
||||
public static final String EVENT_SUB_MIC_STATUS_CHANGED = "eventSubMicStatusChanged";
|
||||
public static final String EVENT_SUB_AUDIOPLAYDEVICE_CHANGED = "eventSubAudioPlayDeviceChanged";
|
||||
|
||||
public static final String OPEN_CAMERA = "openCamera";
|
||||
public static final String SWITCH_CAMERA = "switchCamera";
|
||||
public static final String MUTE_MIC = "muteMic";
|
||||
public static final String HANDS_FREE = "handsFree";
|
||||
public static final String CALL_STATUS = "callStatus";
|
||||
public static final String CALL_MEDIA_TYPE = "callMediaType";
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.base;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.tencent.qcloud.tuikit.TUICommonDefine;
|
||||
import com.tencent.qcloud.tuikit.TUIVideoView;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallDefine;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallEngine;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.config.OfflinePushInfoConfig;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TUICallingAction {
|
||||
private final Context mContext;
|
||||
|
||||
public TUICallingAction(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public void inviteUser(List<String> userIdList, TUICommonDefine.ValueCallback callback) {
|
||||
TUICallDefine.CallParams params = new TUICallDefine.CallParams();
|
||||
params.offlinePushInfo = OfflinePushInfoConfig.createOfflinePushInfo(mContext);
|
||||
params.timeout = Constants.SIGNALING_MAX_TIME;
|
||||
TUICallEngine.createInstance(mContext).inviteUser(userIdList, params, callback);
|
||||
}
|
||||
|
||||
public void accept(TUICommonDefine.Callback callback) {
|
||||
TUICallEngine.createInstance(mContext).accept(new TUICommonDefine.Callback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
TUICallingStatusManager.sharedInstance(mContext).updateCallStatus(TUICallDefine.Status.Accept);
|
||||
if (callback != null) {
|
||||
callback.onSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errCode, String errMsg) {
|
||||
TUICallingStatusManager.sharedInstance(mContext).updateCallStatus(TUICallDefine.Status.None);
|
||||
if (callback != null) {
|
||||
callback.onError(errCode, errMsg);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void reject(TUICommonDefine.Callback callback) {
|
||||
TUICallEngine.createInstance(mContext).reject(new TUICommonDefine.Callback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
TUICallingStatusManager.sharedInstance(mContext).updateCallStatus(TUICallDefine.Status.None);
|
||||
if (callback != null) {
|
||||
callback.onSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errCode, String errMsg) {
|
||||
TUICallingStatusManager.sharedInstance(mContext).updateCallStatus(TUICallDefine.Status.None);
|
||||
if (callback != null) {
|
||||
callback.onError(errCode, errMsg);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void hangup(TUICommonDefine.Callback callback) {
|
||||
TUICallEngine.createInstance(mContext).hangup(new TUICommonDefine.Callback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
TUICallingStatusManager.sharedInstance(mContext).updateCallStatus(TUICallDefine.Status.None);
|
||||
if (callback != null) {
|
||||
callback.onSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errCode, String errMsg) {
|
||||
TUICallingStatusManager.sharedInstance(mContext).updateCallStatus(TUICallDefine.Status.None);
|
||||
if (callback != null) {
|
||||
callback.onError(errCode, errMsg);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void switchCallMediaType(TUICallDefine.MediaType callMediaType) {
|
||||
TUICallEngine.createInstance(mContext).switchCallMediaType(callMediaType);
|
||||
}
|
||||
|
||||
public void openCamera(TUICommonDefine.Camera camera, TUIVideoView videoView, TUICommonDefine.Callback callback) {
|
||||
TUICallEngine.createInstance(mContext).openCamera(camera, videoView, new TUICommonDefine.Callback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
TUICallDefine.Status status = TUICallingStatusManager.sharedInstance(mContext).getCallStatus();
|
||||
if (!TUICallDefine.Status.None.equals(status)) {
|
||||
TUICommonDefine.Camera camera = TUICallingStatusManager.sharedInstance(mContext).getFrontCamera();
|
||||
TUICallingStatusManager.sharedInstance(mContext).updateCameraOpenStatus(true, camera);
|
||||
TUICallingStatusManager.sharedInstance(mContext).updateFrontCameraStatus(camera);
|
||||
}
|
||||
|
||||
if (callback != null) {
|
||||
callback.onSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errCode, String errMsg) {
|
||||
if (callback != null) {
|
||||
callback.onError(errCode, errMsg);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void closeCamera() {
|
||||
TUICallEngine.createInstance(mContext).closeCamera();
|
||||
TUICommonDefine.Camera frontCamera = TUICallingStatusManager.sharedInstance(mContext).getFrontCamera();
|
||||
TUICallingStatusManager.sharedInstance(mContext).updateCameraOpenStatus(false, frontCamera);
|
||||
}
|
||||
|
||||
public void switchCamera(TUICommonDefine.Camera camera) {
|
||||
TUICallEngine.createInstance(mContext).switchCamera(camera);
|
||||
TUICallingStatusManager.sharedInstance(mContext).updateFrontCameraStatus(camera);
|
||||
}
|
||||
|
||||
public void openMicrophone(TUICommonDefine.Callback callback) {
|
||||
TUICallEngine.createInstance(mContext).openMicrophone(callback);
|
||||
TUICallingStatusManager.sharedInstance(mContext).updateMicMuteStatus(false);
|
||||
}
|
||||
|
||||
public void closeMicrophone() {
|
||||
TUICallEngine.createInstance(mContext).closeMicrophone();
|
||||
TUICallingStatusManager.sharedInstance(mContext).updateMicMuteStatus(true);
|
||||
}
|
||||
|
||||
public void selectAudioPlaybackDevice(TUICommonDefine.AudioPlaybackDevice device) {
|
||||
TUICallEngine.createInstance(mContext).selectAudioPlaybackDevice(device);
|
||||
TUICallingStatusManager.sharedInstance(mContext).updateAudioPlaybackDevice(device);
|
||||
}
|
||||
|
||||
public void startRemoteView(String userId, TUIVideoView videoView, TUICommonDefine.PlayCallback callback) {
|
||||
TUICallEngine.createInstance(mContext).startRemoteView(userId, videoView, callback);
|
||||
}
|
||||
|
||||
public void stopRemoteView(String userId) {
|
||||
TUICallEngine.createInstance(mContext).stopRemoteView(userId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.base;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.tencent.qcloud.tuicore.TUICore;
|
||||
import com.tencent.qcloud.tuikit.TUICommonDefine;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallDefine;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.TUICallKitImpl;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class TUICallingStatusManager {
|
||||
private static TUICallingStatusManager sInstance;
|
||||
private final Context mContext;
|
||||
|
||||
private boolean mIsCameraOpen;
|
||||
private boolean mIsMicMute;
|
||||
private TUICommonDefine.Camera mIsFrontCamera = TUICommonDefine.Camera.Front;
|
||||
private TUICommonDefine.AudioPlaybackDevice mAudioDevice = TUICommonDefine.AudioPlaybackDevice.Speakerphone;
|
||||
private TUICallDefine.Status mCallStatus = TUICallDefine.Status.None;
|
||||
private TUICallDefine.Role mCallRole = TUICallDefine.Role.None;
|
||||
private TUICallDefine.MediaType mMediaType = TUICallDefine.MediaType.Unknown;
|
||||
private TUICallDefine.Scene mCallScene;
|
||||
private String mGroupId;
|
||||
|
||||
public static TUICallingStatusManager sharedInstance(Context context) {
|
||||
if (null == sInstance) {
|
||||
synchronized (TUICallKitImpl.class) {
|
||||
if (null == sInstance) {
|
||||
sInstance = new TUICallingStatusManager(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private TUICallingStatusManager(Context context) {
|
||||
mContext = context.getApplicationContext();
|
||||
}
|
||||
|
||||
public boolean isCameraOpen() {
|
||||
return mIsCameraOpen;
|
||||
}
|
||||
|
||||
public boolean isMicMute() {
|
||||
return mIsMicMute;
|
||||
}
|
||||
|
||||
public TUICommonDefine.Camera getFrontCamera() {
|
||||
return mIsFrontCamera;
|
||||
}
|
||||
|
||||
public TUICommonDefine.AudioPlaybackDevice getAudioPlaybackDevice() {
|
||||
return mAudioDevice;
|
||||
}
|
||||
|
||||
public TUICallDefine.Status getCallStatus() {
|
||||
return mCallStatus;
|
||||
}
|
||||
|
||||
public void updateCallStatus(TUICallDefine.Status status) {
|
||||
if (mCallStatus.equals(status)) {
|
||||
return;
|
||||
}
|
||||
mCallStatus = status;
|
||||
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put(Constants.CALL_STATUS, status);
|
||||
TUICore.notifyEvent(Constants.EVENT_TUICALLING_CHANGED, Constants.EVENT_SUB_CALL_STATUS_CHANGED, map);
|
||||
}
|
||||
|
||||
public void updateCameraOpenStatus(boolean isOpen, TUICommonDefine.Camera isFrontCamera) {
|
||||
mIsCameraOpen = isOpen;
|
||||
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put(Constants.OPEN_CAMERA, isOpen);
|
||||
if (isOpen) {
|
||||
map.put(Constants.SWITCH_CAMERA, isFrontCamera);
|
||||
}
|
||||
TUICore.notifyEvent(Constants.EVENT_TUICALLING_CHANGED, Constants.EVENT_SUB_CAMERA_OPEN, map);
|
||||
}
|
||||
|
||||
public void updateFrontCameraStatus(TUICommonDefine.Camera isFrontCamera) {
|
||||
mIsFrontCamera = isFrontCamera;
|
||||
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put(Constants.SWITCH_CAMERA, isFrontCamera);
|
||||
TUICore.notifyEvent(Constants.EVENT_TUICALLING_CHANGED, Constants.EVENT_SUB_CAMERA_FRONT, map);
|
||||
}
|
||||
|
||||
public void updateMicMuteStatus(boolean isMicMute) {
|
||||
if (mIsMicMute == isMicMute) {
|
||||
return;
|
||||
}
|
||||
mIsMicMute = isMicMute;
|
||||
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put(Constants.MUTE_MIC, isMicMute);
|
||||
TUICore.notifyEvent(Constants.EVENT_TUICALLING_CHANGED, Constants.EVENT_SUB_MIC_STATUS_CHANGED, map);
|
||||
}
|
||||
|
||||
public void updateAudioPlaybackDevice(TUICommonDefine.AudioPlaybackDevice audioPlaybackDevice) {
|
||||
mAudioDevice = audioPlaybackDevice;
|
||||
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put(Constants.HANDS_FREE, audioPlaybackDevice);
|
||||
TUICore.notifyEvent(Constants.EVENT_TUICALLING_CHANGED, Constants.EVENT_SUB_AUDIOPLAYDEVICE_CHANGED, map);
|
||||
}
|
||||
|
||||
public void setGroupId(String groupId) {
|
||||
mGroupId = groupId;
|
||||
}
|
||||
|
||||
public String getGroupId() {
|
||||
return mGroupId;
|
||||
}
|
||||
|
||||
public void setCallRole(TUICallDefine.Role role) {
|
||||
mCallRole = role;
|
||||
}
|
||||
|
||||
public TUICallDefine.Role getCallRole() {
|
||||
return mCallRole;
|
||||
}
|
||||
|
||||
public TUICallDefine.MediaType getMediaType() {
|
||||
return mMediaType;
|
||||
}
|
||||
|
||||
public void setMediaType(TUICallDefine.MediaType type) {
|
||||
mMediaType = type;
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put(Constants.CALL_MEDIA_TYPE, mMediaType);
|
||||
TUICore.notifyEvent(Constants.EVENT_TUICALLING_CHANGED, Constants.EVENT_SUB_CALL_TYPE_CHANGED, map);
|
||||
}
|
||||
|
||||
public TUICallDefine.Scene getCallScene() {
|
||||
return mCallScene;
|
||||
}
|
||||
|
||||
public void setCallScene(TUICallDefine.Scene scene) {
|
||||
this.mCallScene = scene;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
mIsCameraOpen = false;
|
||||
mIsFrontCamera = TUICommonDefine.Camera.Front;
|
||||
mIsMicMute = false;
|
||||
mAudioDevice = TUICommonDefine.AudioPlaybackDevice.Speakerphone;
|
||||
mCallStatus = TUICallDefine.Status.None;
|
||||
mCallRole = TUICallDefine.Role.None;
|
||||
mMediaType = TUICallDefine.MediaType.Unknown;
|
||||
mCallScene = null;
|
||||
mGroupId = "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.base;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.tencent.qcloud.tuikit.TUIVideoView;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.R;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.utils.ImageLoader;
|
||||
|
||||
public class UserLayout extends RelativeLayout {
|
||||
private TUIVideoView mTUIVideoView;
|
||||
private ImageView mImgUserAvatar;
|
||||
private TextView mTextUserName;
|
||||
private ImageView mImgAudioInput;
|
||||
private ImageView mImgLoading;
|
||||
private boolean mMoveAble;
|
||||
private boolean mMuteAudio = false;
|
||||
private boolean mDisableAudioImage = false;
|
||||
|
||||
public UserLayout(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public UserLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initView();
|
||||
setClickable(true);
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
LayoutInflater.from(getContext()).inflate(R.layout.tuicalling_group_user_layout, this, true);
|
||||
mTUIVideoView = findViewById(R.id.tx_cloud_view);
|
||||
mImgUserAvatar = findViewById(R.id.img_head);
|
||||
mTextUserName = findViewById(R.id.tv_name);
|
||||
mImgAudioInput = findViewById(R.id.iv_audio_input);
|
||||
mImgLoading = (ImageView) findViewById(R.id.img_loading);
|
||||
ImageLoader.loadGifImage(getContext(), mImgLoading, R.drawable.tuicalling_loading);
|
||||
}
|
||||
|
||||
public TUIVideoView getVideoView() {
|
||||
return mTUIVideoView;
|
||||
}
|
||||
|
||||
public void addVideoView(TUIVideoView view) {
|
||||
if (this.mTUIVideoView != null) {
|
||||
this.removeView(this.mTUIVideoView);
|
||||
}
|
||||
|
||||
this.mTUIVideoView = view;
|
||||
this.addView(this.mTUIVideoView);
|
||||
}
|
||||
|
||||
public ImageView getAvatarImage() {
|
||||
return mImgUserAvatar;
|
||||
}
|
||||
|
||||
public void setVideoAvailable(boolean available) {
|
||||
if (available) {
|
||||
mTUIVideoView.setVisibility(VISIBLE);
|
||||
mImgUserAvatar.setVisibility(GONE);
|
||||
mTextUserName.setVisibility(VISIBLE);
|
||||
} else {
|
||||
mTUIVideoView.setVisibility(GONE);
|
||||
mImgUserAvatar.setVisibility(VISIBLE);
|
||||
mTextUserName.setVisibility(VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
public void setRemoteIconAvailable(boolean available) {
|
||||
mImgUserAvatar.setVisibility(available ? VISIBLE : GONE);
|
||||
mTextUserName.setVisibility(available ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
mTextUserName.setText(userName);
|
||||
}
|
||||
|
||||
public void setAudioVolume(int vol, boolean isAudioAvailable) {
|
||||
if (mMuteAudio || mDisableAudioImage) {
|
||||
return;
|
||||
}
|
||||
mImgAudioInput.setVisibility((isAudioAvailable && vol > Constants.MIN_AUDIO_VOLUME) ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
public void muteMic(boolean mute) {
|
||||
mMuteAudio = mute;
|
||||
if (mDisableAudioImage) {
|
||||
return;
|
||||
}
|
||||
mImgAudioInput.setVisibility(mMuteAudio ? GONE : VISIBLE);
|
||||
}
|
||||
|
||||
public void disableAudioImage(boolean enable) {
|
||||
mDisableAudioImage = enable;
|
||||
}
|
||||
|
||||
public void startLoading() {
|
||||
mImgLoading.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
public void stopLoading() {
|
||||
mImgLoading.setVisibility(GONE);
|
||||
}
|
||||
|
||||
public boolean isMoveAble() {
|
||||
return mMoveAble;
|
||||
}
|
||||
|
||||
public void setMoveAble(boolean enable) {
|
||||
mMoveAble = enable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.base;
|
||||
|
||||
public class UserLayoutEntity {
|
||||
public String userId = "";
|
||||
public UserLayout layout;
|
||||
public CallingUserModel userModel;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.config;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.tencent.qcloud.tuicore.TUILogin;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallDefine;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.R;
|
||||
|
||||
public class OfflinePushInfoConfig {
|
||||
|
||||
//Customize offline push information
|
||||
public static TUICallDefine.OfflinePushInfo createOfflinePushInfo(Context context) {
|
||||
TUICallDefine.OfflinePushInfo pushInfo = new TUICallDefine.OfflinePushInfo();
|
||||
pushInfo.setTitle(TUILogin.getNickName());
|
||||
pushInfo.setDesc(context.getString(R.string.tuicalling_have_a_new_call));
|
||||
// OPPO必须设置ChannelID才可以收到推送消息,这个channelID需要和控制台一致
|
||||
// OPPO must set a ChannelID to receive push messages. This channelID needs to be the same as the console.
|
||||
pushInfo.setAndroidOPPOChannelID("tuikit");
|
||||
pushInfo.setIgnoreIOSBadge(false);
|
||||
pushInfo.setIOSSound("phone_ringing.mp3");
|
||||
//VIVO message type: 0-push message, 1-System message(have a higher delivery rate)
|
||||
pushInfo.setAndroidVIVOClassification(1);
|
||||
return pushInfo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.event
|
||||
|
||||
/**
|
||||
* @author nanfeifei
|
||||
* @time 2023/7/12 9:59
|
||||
* @description
|
||||
*/
|
||||
class CallBackEvent(val callStatus: Int) {
|
||||
companion object{
|
||||
const val CALL_BEGIN = 1
|
||||
const val CALL_CANCEL = 2
|
||||
const val CALL_END = 3
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.extensions;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaPlayer;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.tencent.qcloud.tuicore.util.SPUtils;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.R;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class CallingBellFeature {
|
||||
public static final String PROFILE_TUICALLING = "per_profile_tuicalling";
|
||||
public static final String PROFILE_CALL_BELL = "per_call_bell";
|
||||
public static final String PROFILE_MUTE_MODE = "per_mute_mode";
|
||||
|
||||
private Context mContext;
|
||||
private final MediaPlayer mMediaPlayer;
|
||||
private Handler mHandler;
|
||||
private int mCallingBellResourceId;
|
||||
private String mCallingBellResourcePath;
|
||||
|
||||
public CallingBellFeature(Context context) {
|
||||
mContext = context.getApplicationContext();
|
||||
mMediaPlayer = new MediaPlayer();
|
||||
mCallingBellResourceId = -1;
|
||||
mCallingBellResourcePath = "";
|
||||
}
|
||||
|
||||
public void startDialingMusic() {
|
||||
start("", R.raw.phone_dialing, 0);
|
||||
}
|
||||
|
||||
public void startRing() {
|
||||
String path = SPUtils.getInstance(PROFILE_TUICALLING).getString(PROFILE_CALL_BELL, "");
|
||||
if (TextUtils.isEmpty(path)) {
|
||||
start("", R.raw.phone_ringing, 0);
|
||||
} else {
|
||||
start(path, -1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void stopMusic() {
|
||||
stop();
|
||||
}
|
||||
|
||||
private void start(String resPath, final int resId, long duration) {
|
||||
preHandler();
|
||||
if (TextUtils.isEmpty(resPath) && (-1 == resId)) {
|
||||
return;
|
||||
}
|
||||
if ((-1 != resId && (mCallingBellResourceId == resId))
|
||||
|| (!TextUtils.isEmpty(resPath) && TextUtils.equals(mCallingBellResourcePath, resPath))) {
|
||||
return;
|
||||
}
|
||||
AssetFileDescriptor afd0 = null;
|
||||
if (!TextUtils.isEmpty(resPath) && isUrl(resPath)) {
|
||||
return;
|
||||
} else if (!TextUtils.isEmpty(resPath) && new File(resPath).exists()) {
|
||||
mCallingBellResourcePath = resPath;
|
||||
} else if (-1 != resId) {
|
||||
mCallingBellResourceId = resId;
|
||||
afd0 = mContext.getResources().openRawResourceFd(resId);
|
||||
if (afd0 == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final AssetFileDescriptor afd = afd0;
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mMediaPlayer.isPlaying()) {
|
||||
mMediaPlayer.stop();
|
||||
}
|
||||
mMediaPlayer.setOnCompletionListener(null);
|
||||
mMediaPlayer.reset();
|
||||
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
|
||||
try {
|
||||
if (null != afd) {
|
||||
mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
|
||||
} else if (!TextUtils.isEmpty(mCallingBellResourcePath)) {
|
||||
mMediaPlayer.setDataSource(mCallingBellResourcePath);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
|
||||
@Override
|
||||
public void onCompletion(MediaPlayer mp) {
|
||||
stop();
|
||||
}
|
||||
});
|
||||
try {
|
||||
mMediaPlayer.prepare();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
mMediaPlayer.start();
|
||||
}
|
||||
});
|
||||
if (duration > 0) {
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
stop();
|
||||
}
|
||||
}, duration);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isUrl(String url) {
|
||||
return url.startsWith("http://") || url.startsWith("https://");
|
||||
}
|
||||
|
||||
private void preHandler() {
|
||||
if (null != mHandler) {
|
||||
return;
|
||||
}
|
||||
HandlerThread thread = new HandlerThread("Handler-MediaPlayer");
|
||||
thread.start();
|
||||
mHandler = new Handler(thread.getLooper());
|
||||
}
|
||||
|
||||
private int getResId() {
|
||||
return mCallingBellResourceId;
|
||||
}
|
||||
|
||||
private void stop() {
|
||||
if (null == mHandler) {
|
||||
return;
|
||||
}
|
||||
if ((-1 == getResId()) && TextUtils.isEmpty(mCallingBellResourcePath)) {
|
||||
return;
|
||||
}
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mMediaPlayer.isPlaying()) {
|
||||
mMediaPlayer.stop();
|
||||
}
|
||||
mCallingBellResourceId = -1;
|
||||
mCallingBellResourcePath = "";
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.extensions;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.service.TUICallService;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.utils.DeviceUtils;
|
||||
|
||||
public class CallingKeepAliveFeature {
|
||||
private Context mContext;
|
||||
private boolean mEnableKeepAlive = true;
|
||||
|
||||
public CallingKeepAliveFeature(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public void enableKeepAlive(boolean enable) {
|
||||
mEnableKeepAlive = enable;
|
||||
}
|
||||
|
||||
public void startKeepAlive() {
|
||||
if (!mEnableKeepAlive) {
|
||||
return;
|
||||
}
|
||||
TUICallService.start(mContext);
|
||||
}
|
||||
|
||||
public void stopKeepAlive() {
|
||||
if (DeviceUtils.isServiceRunning(mContext, TUICallService.class.getName())) {
|
||||
TUICallService.stop(mContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.extensions;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.PowerManager;
|
||||
|
||||
public class CallingScreenSensorFeature {
|
||||
private Context mContext;
|
||||
private SensorManager mSensorManager;
|
||||
private SensorEventListener mSensorEventListener;
|
||||
/**
|
||||
* 开启或者关闭贴耳息屏(这个不要开启,OPPO手机有问题)
|
||||
*/
|
||||
private boolean mEnableCloseScreenNearEar = false;
|
||||
|
||||
public CallingScreenSensorFeature(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public void enableScreenSensor(boolean enable) {
|
||||
mEnableCloseScreenNearEar = enable;
|
||||
}
|
||||
|
||||
public void registerSensorEventListener() {
|
||||
if (!mEnableCloseScreenNearEar) {
|
||||
return;
|
||||
}
|
||||
if (null != mSensorManager) {
|
||||
return;
|
||||
}
|
||||
mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
|
||||
Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
|
||||
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
|
||||
final PowerManager.WakeLock wakeLock = pm.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,
|
||||
"TUICalling:TRTCAudioCallWakeLock");
|
||||
mSensorEventListener = new SensorEventListener() {
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
if (event.sensor.getType() == Sensor.TYPE_PROXIMITY) {
|
||||
if (event.values[0] == 0.0) {
|
||||
if (wakeLock.isHeld()) {
|
||||
return;
|
||||
} else {
|
||||
wakeLock.acquire();
|
||||
}
|
||||
} else {
|
||||
if (!wakeLock.isHeld()) {
|
||||
return;
|
||||
} else {
|
||||
wakeLock.setReferenceCounted(false);
|
||||
wakeLock.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
|
||||
}
|
||||
};
|
||||
mSensorManager.registerListener(mSensorEventListener, sensor, SensorManager.SENSOR_DELAY_FASTEST);
|
||||
}
|
||||
|
||||
public void unregisterSensorEventListener() {
|
||||
if (null != mSensorManager && null != mSensorEventListener) {
|
||||
Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
|
||||
mSensorManager.unregisterListener(mSensorEventListener, sensor);
|
||||
mSensorManager = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.internal;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.tencent.qcloud.tuicore.TUIConstants;
|
||||
import com.tencent.qcloud.tuicore.TUICore;
|
||||
import com.tencent.qcloud.tuicore.TUILogin;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.TUICallKitImpl;
|
||||
|
||||
/**
|
||||
* `TUICallKit` uses `ContentProvider` to be registered with `TUICore`.
|
||||
* (`TUICore` is the connection and communication class of each component)
|
||||
*/
|
||||
public final class ServiceInitializer extends ContentProvider {
|
||||
public void init(Context context) {
|
||||
TUICallingService callingService = TUICallingService.sharedInstance();
|
||||
callingService.init(context);
|
||||
TUICore.registerService(TUIConstants.TUICalling.SERVICE_NAME, callingService);
|
||||
TUICore.registerExtension(TUIConstants.TUIChat.EXTENSION_INPUT_MORE_AUDIO_CALL, callingService);
|
||||
TUICore.registerExtension(TUIConstants.TUIChat.EXTENSION_INPUT_MORE_VIDEO_CALL, callingService);
|
||||
|
||||
TUIAudioMessageRecordService audioRecordService = new TUIAudioMessageRecordService(context);
|
||||
TUICore.registerService(TUIConstants.TUICalling.SERVICE_NAME_AUDIO_RECORD, audioRecordService);
|
||||
|
||||
if (context instanceof Application) {
|
||||
((Application) context).registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
|
||||
private int foregroundActivities = 0;
|
||||
private boolean isChangingConfiguration;
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Activity activity, Bundle bundle) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityStarted(Activity activity) {
|
||||
foregroundActivities++;
|
||||
if (foregroundActivities == 1 && !isChangingConfiguration) {
|
||||
if (TUILogin.isUserLogined()) {
|
||||
TUICallKitImpl.createInstance(context).queryOfflineCall();
|
||||
}
|
||||
}
|
||||
isChangingConfiguration = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResumed(Activity activity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityPaused(Activity activity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityStopped(Activity activity) {
|
||||
foregroundActivities--;
|
||||
isChangingConfiguration = activity.isChangingConfigurations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityDestroyed(Activity activity) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
Context appContext = getContext().getApplicationContext();
|
||||
init(appContext);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
|
||||
@Nullable String[] selectionArgs, @Nullable String sortOrder) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getType(@NonNull Uri uri) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection,
|
||||
@Nullable String[] selectionArgs) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,335 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.internal;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.AudioFocusRequest;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.tencent.qcloud.tuicore.TUIConstants;
|
||||
import com.tencent.qcloud.tuicore.TUICore;
|
||||
import com.tencent.qcloud.tuicore.interfaces.ITUINotification;
|
||||
import com.tencent.qcloud.tuicore.interfaces.ITUIService;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallDefine;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallEngine;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallObserver;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.impl.base.TUILog;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.TUICallingStatusManager;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.utils.PermissionRequest;
|
||||
import com.tencent.trtc.TRTCCloud;
|
||||
import com.tencent.trtc.TRTCCloudDef;
|
||||
import com.tencent.trtc.TRTCCloudListener;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class TUIAudioMessageRecordService implements ITUIService, ITUINotification {
|
||||
private static final String TAG = "TUIAudioMessageRecordService";
|
||||
|
||||
private Context mContext;
|
||||
private AudioRecordInfo mAudioRecordInfo;
|
||||
|
||||
private AudioFocusRequest mFocusRequest;
|
||||
private AudioManager mAudioManager;
|
||||
private AudioManager.OnAudioFocusChangeListener onFocusChangeListener;
|
||||
|
||||
public TUIAudioMessageRecordService(Context context) {
|
||||
mContext = context.getApplicationContext();
|
||||
TUICore.registerEvent(TUIConstants.TUILogin.EVENT_LOGIN_STATE_CHANGED,
|
||||
TUIConstants.TUILogin.EVENT_SUB_KEY_USER_LOGIN_SUCCESS, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object onCall(String method, Map<String, Object> param) {
|
||||
if (TextUtils.equals(TUIConstants.TUICalling.METHOD_NAME_START_RECORD_AUDIO_MESSAGE, method)) {
|
||||
if (param == null) {
|
||||
TUILog.e(TAG, "startRecordAudioMessage failed, param is empty");
|
||||
notifyAudioMessageRecordEvent(TUIConstants.TUICalling.EVENT_SUB_KEY_RECORD_START,
|
||||
TUIConstants.TUICalling.ERROR_INVALID_PARAM, null);
|
||||
return false;
|
||||
}
|
||||
|
||||
//如果当前在通话中,不支持录音
|
||||
if (!TUICallDefine.Status.None.equals(TUICallingStatusManager.sharedInstance(mContext).getCallStatus())) {
|
||||
TUILog.e(TAG, "startRecordAudioMessage failed, The current call status does not support recording");
|
||||
notifyAudioMessageRecordEvent(TUIConstants.TUICalling.EVENT_SUB_KEY_RECORD_START,
|
||||
TUIConstants.TUICalling.ERROR_STATUS_IN_CALL, null);
|
||||
return false;
|
||||
}
|
||||
|
||||
//当前已经在录音中
|
||||
if (mAudioRecordInfo != null) {
|
||||
TUILog.e(TAG, "startRecordAudioMessage failed, The recording is not over, It cannot be called again");
|
||||
notifyAudioMessageRecordEvent(TUIConstants.TUICalling.EVENT_SUB_KEY_RECORD_START,
|
||||
TUIConstants.TUICalling.ERROR_STATUS_IS_AUDIO_RECORDING, null);
|
||||
return false;
|
||||
}
|
||||
|
||||
//获取麦克风权限
|
||||
int microphone = PermissionRequest.PERMISSION_MICROPHONE;
|
||||
PermissionRequest.requestPermission(mContext, microphone, new PermissionRequest.PermissionCallback() {
|
||||
@Override
|
||||
public void onGranted() {
|
||||
super.onGranted();
|
||||
|
||||
//获取音频焦点
|
||||
initAudioFocusManager();
|
||||
if (requestAudioFocus() != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
||||
TUILog.e(TAG, "startRecordAudioMessage failed, Failed to obtain audio focus");
|
||||
notifyAudioMessageRecordEvent(TUIConstants.TUICalling.EVENT_SUB_KEY_RECORD_START,
|
||||
TUIConstants.TUICalling.ERROR_REQUEST_AUDIO_FOCUS_FAILED, null);
|
||||
return;
|
||||
}
|
||||
|
||||
mAudioRecordInfo = new AudioRecordInfo();
|
||||
if (param.containsKey(TUIConstants.TUICalling.PARAM_NAME_AUDIO_PATH)) {
|
||||
mAudioRecordInfo.path = (String) param.get(TUIConstants.TUICalling.PARAM_NAME_AUDIO_PATH);
|
||||
}
|
||||
if (param.containsKey(TUIConstants.TUICalling.PARAM_NAME_SDK_APP_ID)) {
|
||||
mAudioRecordInfo.sdkAppId = (int) param.get(TUIConstants.TUICalling.PARAM_NAME_SDK_APP_ID);
|
||||
}
|
||||
if (param.containsKey(TUIConstants.TUICalling.PARAM_NAME_AUDIO_SIGNATURE)) {
|
||||
mAudioRecordInfo.signature =
|
||||
(String) param.get(TUIConstants.TUICalling.PARAM_NAME_AUDIO_SIGNATURE);
|
||||
}
|
||||
|
||||
//开启音频采集
|
||||
TRTCCloud.sharedInstance(mContext).setListener(mTRTCCloudListener);
|
||||
startRecordAudioMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDialogRefused() {
|
||||
super.onDialogRefused();
|
||||
notifyAudioMessageRecordEvent(TUIConstants.TUICalling.EVENT_SUB_KEY_RECORD_START,
|
||||
TUIConstants.TUICalling.ERROR_MIC_PERMISSION_REFUSED, null);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TextUtils.equals(TUIConstants.TUICalling.METHOD_NAME_STOP_RECORD_AUDIO_MESSAGE, method)) {
|
||||
stopRecordAudioMessage();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private TRTCCloudListener mTRTCCloudListener = new TRTCCloudListener() {
|
||||
@Override
|
||||
public void onError(int errCode, String errMsg, Bundle extraInfo) {
|
||||
super.onError(errCode, errMsg, extraInfo);
|
||||
if (errCode == TUIConstants.TUICalling.ERR_MIC_START_FAIL
|
||||
|| errCode == TUIConstants.TUICalling.ERR_MIC_NOT_AUTHORIZED
|
||||
|| errCode == TUIConstants.TUICalling.ERR_MIC_SET_PARAM_FAIL
|
||||
|| errCode == TUIConstants.TUICalling.ERR_MIC_OCCUPY) {
|
||||
notifyAudioMessageRecordEvent(TUIConstants.TUICalling.EVENT_SUB_KEY_RECORD_START, errCode, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocalRecordBegin(int errCode, String storagePath) {
|
||||
super.onLocalRecordBegin(errCode, storagePath);
|
||||
int tempCode = convertErrorCode("onLocalRecordBegin", errCode);
|
||||
if (errCode == TUIConstants.TUICalling.ERROR_NONE) {
|
||||
TRTCCloud.sharedInstance(mContext).startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_SPEECH);
|
||||
}
|
||||
notifyAudioMessageRecordEvent(TUIConstants.TUICalling.EVENT_SUB_KEY_RECORD_START, tempCode, storagePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocalRecordComplete(int errCode, String storagePath) {
|
||||
super.onLocalRecordComplete(errCode, storagePath);
|
||||
int tempCode = convertErrorCode("onLocalRecordComplete", errCode);
|
||||
notifyAudioMessageRecordEvent(TUIConstants.TUICalling.EVENT_SUB_KEY_RECORD_STOP, tempCode, storagePath);
|
||||
}
|
||||
};
|
||||
|
||||
private TUICallObserver mCallObserver = new TUICallObserver() {
|
||||
@Override
|
||||
public void onCallReceived(String callerId, List<String> calleeIdList,
|
||||
String groupId, TUICallDefine.MediaType callMediaType) {
|
||||
super.onCallReceived(callerId, calleeIdList, groupId, callMediaType);
|
||||
//收到通话邀请,停止录制
|
||||
stopRecordAudioMessage();
|
||||
}
|
||||
};
|
||||
|
||||
private void startRecordAudioMessage() {
|
||||
if (mAudioRecordInfo == null) {
|
||||
TUILog.e(TAG, "startRecordAudioMessage failed, audioRecordInfo is empty");
|
||||
return;
|
||||
}
|
||||
TUILog.i(TAG, "startRecordAudioMessage, mAudioRecordInfo: " + mAudioRecordInfo);
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
try {
|
||||
jsonObject.put("api", "startRecordAudioMessage");
|
||||
JSONObject params = new JSONObject();
|
||||
params.put(TUIConstants.TUICalling.PARAM_NAME_SDK_APP_ID, mAudioRecordInfo.sdkAppId);
|
||||
params.put(TUIConstants.TUICalling.PARAM_NAME_AUDIO_PATH, mAudioRecordInfo.path);
|
||||
params.put("key", mAudioRecordInfo.signature);
|
||||
jsonObject.put("params", params);
|
||||
TRTCCloud.sharedInstance(mContext).callExperimentalAPI(jsonObject.toString());
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void stopRecordAudioMessage() {
|
||||
if (mAudioRecordInfo == null) {
|
||||
TUILog.w(TAG, "stopRecordAudioMessage, current recording status is Idle,do not need to stop");
|
||||
return;
|
||||
}
|
||||
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
try {
|
||||
jsonObject.put("api", "stopRecordAudioMessage");
|
||||
JSONObject params = new JSONObject();
|
||||
jsonObject.put("params", params);
|
||||
TRTCCloud.sharedInstance(mContext).callExperimentalAPI(jsonObject.toString());
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
TUILog.i(TAG, "stopRecordAudioMessage, stopLocalAudio");
|
||||
TRTCCloud.sharedInstance(mContext).stopLocalAudio();
|
||||
//清空录制信息
|
||||
mAudioRecordInfo = null;
|
||||
//释放音频焦点
|
||||
abandonAudioFocus();
|
||||
}
|
||||
|
||||
private void notifyAudioMessageRecordEvent(String method, int errCode, String path) {
|
||||
TUILog.i(TAG, "notifyAudioMessageRecordEvent, method: " + method + ",errCode: " + errCode + ",path: " + path);
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("errorCode", errCode);
|
||||
map.put(TUIConstants.TUICalling.PARAM_NAME_AUDIO_PATH, path);
|
||||
TUICore.notifyEvent(TUIConstants.TUICalling.EVENT_KEY_RECORD_AUDIO_MESSAGE, method, map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotifyEvent(String key, String subKey, Map<String, Object> param) {
|
||||
if (TUIConstants.TUILogin.EVENT_LOGIN_STATE_CHANGED.equals(key)
|
||||
&& TUIConstants.TUILogin.EVENT_SUB_KEY_USER_LOGIN_SUCCESS.equals(subKey)) {
|
||||
TUICallEngine.createInstance(mContext).addObserver(mCallObserver);
|
||||
}
|
||||
}
|
||||
|
||||
private void initAudioFocusManager() {
|
||||
if (mAudioManager == null) {
|
||||
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
}
|
||||
if (onFocusChangeListener == null) {
|
||||
onFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() {
|
||||
@Override
|
||||
public void onAudioFocusChange(int focusChange) {
|
||||
switch (focusChange) {
|
||||
case AudioManager.AUDIOFOCUS_GAIN:
|
||||
break;
|
||||
case AudioManager.AUDIOFOCUS_LOSS:
|
||||
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
|
||||
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
|
||||
//其他应用占用焦点的时候,停止录制
|
||||
stopRecordAudioMessage();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
AudioAttributes attributes = null;
|
||||
//android 5.0
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
attributes = new AudioAttributes.Builder()
|
||||
.setUsage(AudioAttributes.USAGE_MEDIA)
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
|
||||
.build();
|
||||
}
|
||||
//android 8.0
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
mFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT)
|
||||
.setWillPauseWhenDucked(true)
|
||||
.setAudioAttributes(attributes)
|
||||
.setOnAudioFocusChangeListener(onFocusChangeListener)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
private int requestAudioFocus() {
|
||||
if (mAudioManager == null) {
|
||||
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
|
||||
}
|
||||
int result;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
result = mAudioManager.requestAudioFocus(mFocusRequest);
|
||||
} else {
|
||||
result = mAudioManager.requestAudioFocus(onFocusChangeListener, AudioManager.STREAM_MUSIC,
|
||||
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private int abandonAudioFocus() {
|
||||
if (mAudioManager == null) {
|
||||
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
|
||||
}
|
||||
int result;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
result = mAudioManager.abandonAudioFocusRequest(mFocusRequest);
|
||||
} else {
|
||||
result = mAudioManager.abandonAudioFocus(onFocusChangeListener);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private int convertErrorCode(String method, int errorCode) {
|
||||
int targetCode;
|
||||
switch (errorCode) {
|
||||
case -1:
|
||||
targetCode = "onLocalRecordBegin".equals(method) ? TUIConstants.TUICalling.ERROR_RECORD_INIT_FAILED
|
||||
: TUIConstants.TUICalling.ERROR_RECORD_FAILED;
|
||||
break;
|
||||
case -2:
|
||||
targetCode = TUIConstants.TUICalling.ERROR_PATH_FORMAT_NOT_SUPPORT;
|
||||
break;
|
||||
case -3:
|
||||
targetCode = TUIConstants.TUICalling.ERROR_NO_MESSAGE_TO_RECORD;
|
||||
break;
|
||||
case -4:
|
||||
targetCode = TUIConstants.TUICalling.ERROR_SIGNATURE_ERROR;
|
||||
break;
|
||||
case -5:
|
||||
targetCode = TUIConstants.TUICalling.ERROR_SIGNATURE_EXPIRED;
|
||||
break;
|
||||
default:
|
||||
targetCode = TUIConstants.TUICalling.ERROR_NONE;
|
||||
break;
|
||||
}
|
||||
return targetCode;
|
||||
}
|
||||
|
||||
class AudioRecordInfo {
|
||||
public String path; // 录制文件地址
|
||||
public int sdkAppId; // 应用的 SDKAppID
|
||||
public String signature; // AI 降噪签名
|
||||
|
||||
public AudioRecordInfo() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AudioRecordInfo{"
|
||||
+ "path=" + path
|
||||
+ ", SDKAppID=" + sdkAppId
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.internal;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.tencent.imsdk.v2.V2TIMConversation;
|
||||
import com.tencent.qcloud.tuicore.TUIConstants;
|
||||
import com.tencent.qcloud.tuicore.TUICore;
|
||||
import com.tencent.qcloud.tuicore.interfaces.ITUIExtension;
|
||||
import com.tencent.qcloud.tuicore.interfaces.ITUINotification;
|
||||
import com.tencent.qcloud.tuicore.interfaces.ITUIService;
|
||||
import com.tencent.qcloud.tuikit.TUICommonDefine;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallDefine;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallEngine;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.R;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.TUICallKit;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* `TUICore` call (if the `TUICore` module is not imported, use `TUICallKitImpl` instead)
|
||||
*/
|
||||
final class TUICallingService implements ITUINotification, ITUIService, ITUIExtension {
|
||||
|
||||
private static final String TAG = "TUICallingService";
|
||||
|
||||
private static final TUICallingService INSTANCE = new TUICallingService();
|
||||
|
||||
static TUICallingService sharedInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private Context appContext;
|
||||
|
||||
private TUICallingService() {
|
||||
|
||||
}
|
||||
|
||||
public void init(Context context) {
|
||||
appContext = context;
|
||||
TUICore.registerEvent(TUIConstants.TUILogin.EVENT_IMSDK_INIT_STATE_CHANGED,
|
||||
TUIConstants.TUILogin.EVENT_SUB_KEY_START_INIT, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object onCall(String method, Map<String, Object> param) {
|
||||
Log.i(TAG, "onCall, method: " + method + " ,param: " + param);
|
||||
|
||||
if (null != param && TextUtils.equals(TUIConstants.TUICalling.METHOD_NAME_ENABLE_FLOAT_WINDOW, method)) {
|
||||
boolean enableFloatWindow = (boolean) param.get(TUIConstants.TUICalling.PARAM_NAME_ENABLE_FLOAT_WINDOW);
|
||||
Log.i(TAG, "onCall, enableFloatWindow: " + enableFloatWindow);
|
||||
TUICallKit.createInstance(appContext).enableFloatWindow(enableFloatWindow);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (null != param && TextUtils.equals(TUIConstants.TUICalling.METHOD_NAME_ENABLE_MULTI_DEVICE, method)) {
|
||||
boolean enable = (boolean) param.get(TUIConstants.TUICalling.PARAM_NAME_ENABLE_MULTI_DEVICE);
|
||||
Log.i(TAG, "onCall, enableMultiDevice: " + enable);
|
||||
TUICallEngine.createInstance(appContext).enableMultiDeviceAbility(enable, new TUICommonDefine.Callback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errCode, String errMsg) {
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
if (null != param && TextUtils.equals(TUIConstants.TUICalling.METHOD_NAME_CALL, method)) {
|
||||
String[] userIDs = (String[]) param.get(TUIConstants.TUICalling.PARAM_NAME_USERIDS);
|
||||
String typeString = (String) param.get(TUIConstants.TUICalling.PARAM_NAME_TYPE);
|
||||
String groupID = (String) param.get(TUIConstants.TUICalling.PARAM_NAME_GROUPID);
|
||||
|
||||
List<String> userIdList = new ArrayList<>(Arrays.asList(userIDs));
|
||||
TUICallDefine.MediaType mediaType = TUICallDefine.MediaType.Unknown;
|
||||
if (TUIConstants.TUICalling.TYPE_AUDIO.equals(typeString)) {
|
||||
mediaType = TUICallDefine.MediaType.Audio;
|
||||
} else if (TUIConstants.TUICalling.TYPE_VIDEO.equals(typeString)) {
|
||||
mediaType = TUICallDefine.MediaType.Video;
|
||||
}
|
||||
if (!TextUtils.isEmpty(groupID)) {
|
||||
TUICallKit.createInstance(appContext).groupCall(groupID, userIdList, mediaType);
|
||||
} else if (userIdList.size() == 1) {
|
||||
TUICallKit.createInstance(appContext).call(userIdList.get(0), mediaType);
|
||||
} else {
|
||||
Log.e(TAG, "onCall ignored, groupId is empty and userList is not 1, cannot start call or groupCall");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> onGetExtensionInfo(String key, Map<String, Object> param) {
|
||||
Log.i(TAG, "onGetExtensionInfo, key: " + key + " ,param: " + param);
|
||||
|
||||
Context inflateContext = (Context) param.get(TUIConstants.TUIChat.CONTEXT);
|
||||
if (inflateContext == null) {
|
||||
inflateContext = appContext;
|
||||
}
|
||||
if (inflateContext == null) {
|
||||
return null;
|
||||
}
|
||||
HashMap<String, Object> extensionMap = new HashMap<>();
|
||||
View unitView = LayoutInflater.from(inflateContext).inflate(R.layout.chat_input_more_action, null);
|
||||
ImageView imageView = unitView.findViewById(R.id.imageView);
|
||||
TextView textView = unitView.findViewById(R.id.textView);
|
||||
int actionId = 0;
|
||||
if (TUIConstants.TUIChat.EXTENSION_INPUT_MORE_AUDIO_CALL.equals(key)) {
|
||||
imageView.setImageResource(R.drawable.tuicalling_ic_audio_call);
|
||||
textView.setText(inflateContext.getString(R.string.tuicalling_audio_call));
|
||||
actionId = TUIConstants.TUICalling.ACTION_ID_AUDIO_CALL;
|
||||
} else if (TUIConstants.TUIChat.EXTENSION_INPUT_MORE_VIDEO_CALL.equals(key)) {
|
||||
imageView.setImageResource(R.drawable.tuicalling_ic_video_call);
|
||||
textView.setText(inflateContext.getString(R.string.tuicalling_video_call));
|
||||
actionId = TUIConstants.TUICalling.ACTION_ID_VIDEO_CALL;
|
||||
}
|
||||
final String chatId = (String) param.get(TUIConstants.TUIChat.CHAT_ID);
|
||||
int chatType = (int) param.get(TUIConstants.TUIChat.CHAT_TYPE);
|
||||
if (chatType == V2TIMConversation.V2TIM_GROUP) {
|
||||
unitView.setClickable(false);
|
||||
} else {
|
||||
unitView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
TUICallDefine.MediaType mediaType = TUICallDefine.MediaType.Unknown;
|
||||
if (TUIConstants.TUIChat.EXTENSION_INPUT_MORE_AUDIO_CALL.equals(key)) {
|
||||
mediaType = TUICallDefine.MediaType.Audio;
|
||||
} else if (TUIConstants.TUIChat.EXTENSION_INPUT_MORE_VIDEO_CALL.equals(key)) {
|
||||
mediaType = TUICallDefine.MediaType.Video;
|
||||
}
|
||||
Log.i(TAG, "onGetExtensionInfo, mediaType: " + mediaType + " ,chatId: " + chatId);
|
||||
TUICallKit.createInstance(appContext).call(chatId, mediaType);
|
||||
}
|
||||
});
|
||||
}
|
||||
extensionMap.put(TUIConstants.TUIChat.INPUT_MORE_VIEW, unitView);
|
||||
extensionMap.put(TUIConstants.TUIChat.INPUT_MORE_ACTION_ID, actionId);
|
||||
return extensionMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotifyEvent(String key, String subKey, Map<String, Object> param) {
|
||||
if (TUIConstants.TUILogin.EVENT_IMSDK_INIT_STATE_CHANGED.equals(key)
|
||||
&& TUIConstants.TUILogin.EVENT_SUB_KEY_START_INIT.equals(subKey)) {
|
||||
TUICallKit.createInstance(appContext);
|
||||
adaptiveComponentReport();
|
||||
}
|
||||
}
|
||||
|
||||
private void adaptiveComponentReport() {
|
||||
ITUIService service = TUICore.getService(TUIConstants.TUIChat.SERVICE_NAME);
|
||||
if (service == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
JSONObject params = new JSONObject();
|
||||
params.put("framework", 1);
|
||||
params.put("component", 15);
|
||||
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("api", "setFramework");
|
||||
jsonObject.put("params", params);
|
||||
TUICallEngine.createInstance(appContext).callExperimentalAPI(jsonObject.toString());
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.service;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.utils.DeviceUtils;
|
||||
|
||||
/**
|
||||
* TUICalling组件保活, 确保应用在后台不被系统杀死, 如不需要,可删除.
|
||||
*/
|
||||
public class TUICallService extends Service {
|
||||
private static final int NOTIFICATION_ID = 1001;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
// 获取服务通知
|
||||
Notification notification = createForegroundNotification();
|
||||
//将服务置于启动状态 ,NOTIFICATION_ID指的是创建的通知的ID
|
||||
startForeground(NOTIFICATION_ID, notification);
|
||||
}
|
||||
|
||||
public static void start(Context context) {
|
||||
if (DeviceUtils.isServiceRunning(context, TUICallService.class.getName())) {
|
||||
return;
|
||||
}
|
||||
Intent starter = new Intent(context, TUICallService.class);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.startForegroundService(starter);
|
||||
} else {
|
||||
context.startService(starter);
|
||||
}
|
||||
}
|
||||
|
||||
public static void stop(Context context) {
|
||||
Intent intent = new Intent(context, TUICallService.class);
|
||||
context.stopService(intent);
|
||||
}
|
||||
|
||||
private Notification createForegroundNotification() {
|
||||
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
// 唯一的通知通道的id.
|
||||
String notificationChannelId = "notification_channel_id_01";
|
||||
// Android8.0以上的系统,新建消息通道
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
//用户可见的通道名称
|
||||
String channelName = "TRTC Foreground Service Notification";
|
||||
//通道的重要程度
|
||||
int importance = NotificationManager.IMPORTANCE_HIGH;
|
||||
NotificationChannel notificationChannel = new NotificationChannel(
|
||||
notificationChannelId, channelName, importance);
|
||||
notificationChannel.setDescription("Channel description");
|
||||
//震动
|
||||
notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
|
||||
notificationChannel.enableVibration(true);
|
||||
if (notificationManager != null) {
|
||||
notificationManager.createNotificationChannel(notificationChannel);
|
||||
}
|
||||
}
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, notificationChannelId);
|
||||
//创建通知并返回
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskRemoved(Intent rootIntent) {
|
||||
super.onTaskRemoved(rootIntent);
|
||||
stopSelf();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.utils;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.os.PowerManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class DeviceUtils {
|
||||
|
||||
public static void setScreenLockParams(Window window) {
|
||||
if (null == window) {
|
||||
return;
|
||||
}
|
||||
PowerManager powerManager = (PowerManager) window.getContext().getSystemService(Context.POWER_SERVICE);
|
||||
boolean isScreenOn = powerManager.isScreenOn();
|
||||
if (isScreenOn) {
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
|
||||
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
|
||||
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
} else {
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
|
||||
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
|
||||
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|
||||
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
|
||||
}
|
||||
}
|
||||
|
||||
public static int getScreenWidth(Context context) {
|
||||
DisplayMetrics metric = new DisplayMetrics();
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
wm.getDefaultDisplay().getMetrics(metric);
|
||||
return metric.widthPixels;
|
||||
}
|
||||
|
||||
public static int getScreenHeight(Context context) {
|
||||
DisplayMetrics metric = new DisplayMetrics();
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
wm.getDefaultDisplay().getMetrics(metric);
|
||||
return metric.heightPixels;
|
||||
}
|
||||
|
||||
public static boolean isAppRunningForeground(Context context) {
|
||||
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
List<ActivityManager.RunningAppProcessInfo> runningAppProcessInfos = activityManager.getRunningAppProcesses();
|
||||
if (runningAppProcessInfos == null) {
|
||||
return false;
|
||||
}
|
||||
String packageName = context.getPackageName();
|
||||
for (ActivityManager.RunningAppProcessInfo appProcessInfo : runningAppProcessInfos) {
|
||||
if (appProcessInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
|
||||
&& appProcessInfo.processName.equals(packageName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isServiceRunning(Context context, String className) {
|
||||
if (context == null || TextUtils.isEmpty(className)) {
|
||||
return false;
|
||||
}
|
||||
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
List<ActivityManager.RunningServiceInfo> info = am.getRunningServices(0x7FFFFFFF);
|
||||
if (info == null || info.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
for (ActivityManager.RunningServiceInfo aInfo : info) {
|
||||
if (className.equals(aInfo.service.getClassName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class DisplayUtils {
|
||||
|
||||
public static int dip2px(Context context, float dpValue) {
|
||||
final float scale = context.getResources().getDisplayMetrics().density;
|
||||
return (int) (dpValue * scale + 0.5f);
|
||||
}
|
||||
|
||||
// init stack layout
|
||||
public static ArrayList<RelativeLayout.LayoutParams> initFloatParamList(Context context, int width, int height) {
|
||||
ArrayList<RelativeLayout.LayoutParams> list = new ArrayList<RelativeLayout.LayoutParams>();
|
||||
// the largest layout in the bottom
|
||||
RelativeLayout.LayoutParams layoutParams0 = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
list.add(layoutParams0);
|
||||
|
||||
final int midMargin = dip2px(context, 10);
|
||||
final int lrMargin = dip2px(context, 15);
|
||||
final int bottomMargin = dip2px(context, 50);
|
||||
final int subWidth = dip2px(context, 120);
|
||||
final int subHeight = dip2px(context, 180);
|
||||
for (int i = 2; i >= 0; i--) {
|
||||
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(subWidth, subHeight);
|
||||
layoutParams.leftMargin = width - lrMargin - subWidth;
|
||||
layoutParams.topMargin = height - (bottomMargin + midMargin * (i + 1) + subHeight * i) - subHeight;
|
||||
list.add(layoutParams);
|
||||
}
|
||||
|
||||
for (int i = 2; i >= 0; i--) {
|
||||
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(subWidth, subHeight);
|
||||
layoutParams.leftMargin = lrMargin;
|
||||
layoutParams.topMargin = height - (bottomMargin + midMargin * (i + 1) + subHeight * i) - subHeight;
|
||||
list.add(layoutParams);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
// init one grid layout ,center in the screen
|
||||
public static ArrayList<RelativeLayout.LayoutParams> initGrid1Param(Context context, int width, int height) {
|
||||
int margin = dip2px(context, 10);
|
||||
int grid4W = (width - margin * 2) / 2;
|
||||
int grid4H = (height - margin * 2) / 2;
|
||||
RelativeLayout.LayoutParams layoutParams0 = new RelativeLayout.LayoutParams(grid4W, grid4H);
|
||||
layoutParams0.addRule(RelativeLayout.CENTER_IN_PARENT);
|
||||
|
||||
ArrayList<RelativeLayout.LayoutParams> list = new ArrayList<>();
|
||||
list.add(layoutParams0);
|
||||
return list;
|
||||
}
|
||||
|
||||
// init two grid layout ,split the screen
|
||||
public static ArrayList<RelativeLayout.LayoutParams> initGrid2Param(Context context, int width, int height) {
|
||||
int margin = dip2px(context, 10);
|
||||
int grid4W = (width - margin * 2) / 2;
|
||||
int grid4H = (height - margin * 2) / 2;
|
||||
|
||||
RelativeLayout.LayoutParams layoutParams0 = new RelativeLayout.LayoutParams(width, width);
|
||||
layoutParams0.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
|
||||
// layoutParams0.addRule(RelativeLayout.CENTER_VERTICAL);
|
||||
layoutParams0.leftMargin = margin;
|
||||
layoutParams0.rightMargin = margin;
|
||||
|
||||
RelativeLayout.LayoutParams layoutParams1 = new RelativeLayout.LayoutParams((grid4W/3)*2, (grid4H/3)*2);
|
||||
layoutParams1.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
|
||||
// layoutParams1.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
||||
layoutParams1.leftMargin = margin;
|
||||
layoutParams1.topMargin = width;
|
||||
|
||||
ArrayList<RelativeLayout.LayoutParams> list = new ArrayList<>();
|
||||
list.add(layoutParams1);
|
||||
list.add(layoutParams0);
|
||||
return list;
|
||||
}
|
||||
|
||||
// init three grid layout
|
||||
public static ArrayList<RelativeLayout.LayoutParams> initGrid3Param(Context context, int width, int height) {
|
||||
int margin = dip2px(context, 10);
|
||||
int grid3W = (width - margin * 2) / 2;
|
||||
int grid3H = (height - margin * 2) / 2;
|
||||
|
||||
RelativeLayout.LayoutParams layoutParams0 = new RelativeLayout.LayoutParams(grid3W, grid3H);
|
||||
layoutParams0.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
|
||||
layoutParams0.addRule(RelativeLayout.ALIGN_PARENT_TOP);
|
||||
layoutParams0.topMargin = margin;
|
||||
layoutParams0.leftMargin = margin;
|
||||
|
||||
RelativeLayout.LayoutParams layoutParams1 = new RelativeLayout.LayoutParams(grid3W, grid3H);
|
||||
layoutParams1.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
||||
layoutParams1.addRule(RelativeLayout.ALIGN_PARENT_TOP);
|
||||
layoutParams1.topMargin = margin;
|
||||
layoutParams1.rightMargin = margin;
|
||||
|
||||
RelativeLayout.LayoutParams layoutParams2 = new RelativeLayout.LayoutParams(grid3W, grid3H);
|
||||
layoutParams2.addRule(RelativeLayout.CENTER_HORIZONTAL);
|
||||
layoutParams2.bottomMargin = margin;
|
||||
layoutParams2.topMargin = margin + grid3H;
|
||||
|
||||
ArrayList<RelativeLayout.LayoutParams> list = new ArrayList<>();
|
||||
list.add(layoutParams0);
|
||||
list.add(layoutParams1);
|
||||
list.add(layoutParams2);
|
||||
return list;
|
||||
}
|
||||
|
||||
// init four grid layout
|
||||
public static ArrayList<RelativeLayout.LayoutParams> initGrid4Param(Context context, int width, int height) {
|
||||
int margin = dip2px(context, 10);
|
||||
int grid4W = (width - margin * 2) / 2;
|
||||
int grid4H = (height - margin * 2) / 2;
|
||||
|
||||
RelativeLayout.LayoutParams layoutParams0 = new RelativeLayout.LayoutParams(grid4W, grid4H);
|
||||
layoutParams0.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
|
||||
layoutParams0.addRule(RelativeLayout.ALIGN_PARENT_TOP);
|
||||
layoutParams0.topMargin = margin;
|
||||
layoutParams0.leftMargin = margin;
|
||||
|
||||
RelativeLayout.LayoutParams layoutParams1 = new RelativeLayout.LayoutParams(grid4W, grid4H);
|
||||
layoutParams1.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
||||
layoutParams1.addRule(RelativeLayout.ALIGN_PARENT_TOP);
|
||||
layoutParams1.topMargin = margin;
|
||||
layoutParams1.rightMargin = margin;
|
||||
|
||||
RelativeLayout.LayoutParams layoutParams2 = new RelativeLayout.LayoutParams(grid4W, grid4H);
|
||||
layoutParams2.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
|
||||
layoutParams2.bottomMargin = margin;
|
||||
layoutParams2.topMargin = margin + grid4H;
|
||||
layoutParams2.leftMargin = margin;
|
||||
|
||||
RelativeLayout.LayoutParams layoutParams3 = new RelativeLayout.LayoutParams(grid4W, grid4H);
|
||||
layoutParams3.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
||||
layoutParams3.bottomMargin = margin;
|
||||
layoutParams3.topMargin = margin + grid4H;
|
||||
layoutParams3.rightMargin = margin;
|
||||
|
||||
ArrayList<RelativeLayout.LayoutParams> list = new ArrayList<>();
|
||||
list.add(layoutParams0);
|
||||
list.add(layoutParams1);
|
||||
list.add(layoutParams2);
|
||||
list.add(layoutParams3);
|
||||
return list;
|
||||
}
|
||||
|
||||
// init nine grid layout
|
||||
public static ArrayList<RelativeLayout.LayoutParams> initGrid9Param(Context context, int width, int height) {
|
||||
int margin = dip2px(context, 10);
|
||||
int grid9W = (width - margin * 2) / 3;
|
||||
int grid9H = (height - margin * 2) / 3;
|
||||
|
||||
RelativeLayout.LayoutParams layoutParams0 = new RelativeLayout.LayoutParams(grid9W, grid9H);
|
||||
layoutParams0.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
|
||||
layoutParams0.addRule(RelativeLayout.ALIGN_PARENT_TOP);
|
||||
layoutParams0.topMargin = margin;
|
||||
layoutParams0.leftMargin = margin;
|
||||
|
||||
RelativeLayout.LayoutParams layoutParams1 = new RelativeLayout.LayoutParams(grid9W, grid9H);
|
||||
layoutParams1.addRule(RelativeLayout.ALIGN_PARENT_TOP);
|
||||
layoutParams1.topMargin = margin;
|
||||
layoutParams1.leftMargin = margin + grid9W;
|
||||
|
||||
RelativeLayout.LayoutParams layoutParams2 = new RelativeLayout.LayoutParams(grid9W, grid9H);
|
||||
layoutParams2.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
||||
layoutParams2.addRule(RelativeLayout.ALIGN_PARENT_TOP);
|
||||
layoutParams2.topMargin = margin;
|
||||
layoutParams2.rightMargin = margin;
|
||||
|
||||
RelativeLayout.LayoutParams layoutParams3 = new RelativeLayout.LayoutParams(grid9W, grid9H);
|
||||
layoutParams3.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
|
||||
layoutParams3.leftMargin = margin;
|
||||
layoutParams3.topMargin = margin + grid9H;
|
||||
|
||||
RelativeLayout.LayoutParams layoutParams4 = new RelativeLayout.LayoutParams(grid9W, grid9H);
|
||||
layoutParams4.topMargin = margin + grid9H;
|
||||
layoutParams4.leftMargin = margin + grid9W;
|
||||
|
||||
RelativeLayout.LayoutParams layoutParams5 = new RelativeLayout.LayoutParams(grid9W, grid9H);
|
||||
layoutParams5.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
||||
layoutParams5.topMargin = margin + grid9H;
|
||||
layoutParams5.rightMargin = margin;
|
||||
|
||||
RelativeLayout.LayoutParams layoutParams6 = new RelativeLayout.LayoutParams(grid9W, grid9H);
|
||||
layoutParams6.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
|
||||
layoutParams6.bottomMargin = margin;
|
||||
layoutParams6.leftMargin = margin;
|
||||
layoutParams6.topMargin = margin + grid9H * 2;
|
||||
|
||||
RelativeLayout.LayoutParams layoutParams7 = new RelativeLayout.LayoutParams(grid9W, grid9H);
|
||||
layoutParams7.bottomMargin = margin;
|
||||
layoutParams7.topMargin = margin + grid9H * 2;
|
||||
layoutParams7.leftMargin = margin + grid9W;
|
||||
|
||||
RelativeLayout.LayoutParams layoutParams8 = new RelativeLayout.LayoutParams(grid9W, grid9H);
|
||||
layoutParams8.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
||||
layoutParams8.bottomMargin = margin;
|
||||
layoutParams8.topMargin = margin + grid9H * 2;
|
||||
layoutParams8.rightMargin = margin;
|
||||
|
||||
ArrayList<RelativeLayout.LayoutParams> list = new ArrayList<>();
|
||||
list.add(layoutParams0);
|
||||
list.add(layoutParams1);
|
||||
list.add(layoutParams2);
|
||||
list.add(layoutParams3);
|
||||
list.add(layoutParams4);
|
||||
list.add(layoutParams5);
|
||||
list.add(layoutParams6);
|
||||
list.add(layoutParams7);
|
||||
list.add(layoutParams8);
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.RawRes;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.RequestBuilder;
|
||||
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
|
||||
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public class ImageLoader {
|
||||
private static int radius = 0;
|
||||
|
||||
public static void clear(Context context, ImageView imageView) {
|
||||
Glide.with(context).clear(imageView);
|
||||
}
|
||||
|
||||
public static void loadImage(Context context, ImageView imageView, String url) {
|
||||
loadImage(context, imageView, url, 0, radius);
|
||||
}
|
||||
|
||||
public static void loadImage(Context context, ImageView imageView, String url, @DrawableRes int errorResId) {
|
||||
loadImage(context, imageView, url, errorResId, radius);
|
||||
}
|
||||
|
||||
public static void loadImage(Context context, ImageView imageView, String url, @DrawableRes int errorResId,
|
||||
int radius) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
if (imageView != null && errorResId != 0) {
|
||||
imageView.setImageResource(errorResId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
Glide.with(context).load(url).error(loadTransform(context, errorResId, radius)).into(imageView);
|
||||
}
|
||||
|
||||
public static void loadImage(Context context, ImageView imageView, @RawRes @DrawableRes Integer resourceId) {
|
||||
Glide.with(context).load(resourceId).into(imageView);
|
||||
}
|
||||
|
||||
public static Bitmap getImage(Context context, String url, int width, int height) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
Bitmap bitmap = Glide.with(context)
|
||||
.asBitmap()
|
||||
.load(url)
|
||||
.into(width, height)
|
||||
.get();
|
||||
return bitmap;
|
||||
} catch (ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void loadGifImage(Context context, ImageView imageView, String url) {
|
||||
loadGifImage(context, imageView, url, 0);
|
||||
}
|
||||
|
||||
public static void loadGifImage(Context context, ImageView imageView, String url, @DrawableRes int errorResId) {
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
if (imageView != null && errorResId != 0) {
|
||||
imageView.setImageResource(errorResId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
Glide.with(context).asGif().load(url).into(imageView);
|
||||
}
|
||||
|
||||
public static void loadGifImage(Context context, ImageView imageView, @RawRes @DrawableRes int resourceId) {
|
||||
Glide.with(context).asGif().load(resourceId).into(imageView);
|
||||
}
|
||||
|
||||
private static RequestBuilder<Drawable> loadTransform(Context context, @DrawableRes int placeholderId, int radius) {
|
||||
return Glide.with(context).load(placeholderId)
|
||||
.apply(new RequestOptions().centerCrop().transform(new GlideRoundTransform(context, radius)));
|
||||
}
|
||||
|
||||
public static class GlideRoundTransform extends BitmapTransformation {
|
||||
|
||||
private static float radius = 0f;
|
||||
|
||||
public GlideRoundTransform(Context context, int dp) {
|
||||
radius = Resources.getSystem().getDisplayMetrics().density * dp;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
|
||||
return roundCrop(pool, toTransform);
|
||||
}
|
||||
|
||||
private static Bitmap roundCrop(BitmapPool pool, Bitmap source) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Bitmap result = pool.get(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
|
||||
if (result == null) {
|
||||
result = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
|
||||
}
|
||||
|
||||
Canvas canvas = new Canvas(result);
|
||||
Paint paint = new Paint();
|
||||
paint.setShader(new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
|
||||
paint.setAntiAlias(true);
|
||||
RectF rectF = new RectF(0f, 0f, source.getWidth(), source.getHeight());
|
||||
canvas.drawRoundRect(rectF, radius, radius, paint);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDiskCacheKey(MessageDigest messageDigest) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.net.Uri;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
|
||||
import com.tencent.qcloud.tuicore.util.PermissionRequester;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.utils.BrandUtils;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.utils.PermissionUtils;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.R;
|
||||
|
||||
public class PermissionRequest {
|
||||
public static final int PERMISSION_MICROPHONE = 1;
|
||||
public static final int PERMISSION_CAMERA = 2;
|
||||
|
||||
@IntDef({PERMISSION_MICROPHONE, PERMISSION_CAMERA})
|
||||
public @interface PermissionType {
|
||||
}
|
||||
|
||||
public static void requestPermission(Context context, @PermissionType int type1, @PermissionType int type2,
|
||||
PermissionCallback callback) {
|
||||
requestPermission(context, type2, new PermissionCallback() {
|
||||
@Override
|
||||
public void onGranted() {
|
||||
requestPermission(context, type1, new PermissionCallback() {
|
||||
@Override
|
||||
public void onGranted() {
|
||||
if (null != callback) {
|
||||
callback.onGranted();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDenied() {
|
||||
if (null != callback) {
|
||||
callback.onDenied();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDialogApproved() {
|
||||
if (null != callback) {
|
||||
callback.onDialogApproved();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDialogRefused() {
|
||||
if (null != callback) {
|
||||
callback.onDialogRefused();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDenied() {
|
||||
if (null != callback) {
|
||||
callback.onDenied();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDialogApproved() {
|
||||
if (null != callback) {
|
||||
callback.onDialogApproved();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDialogRefused() {
|
||||
if (null != callback) {
|
||||
callback.onDialogRefused();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void requestPermission(Context context, @PermissionType int type, PermissionCallback callback) {
|
||||
String permission = null;
|
||||
String reason = null;
|
||||
String reasonTitle = null;
|
||||
String deniedAlert = null;
|
||||
ApplicationInfo applicationInfo = context.getApplicationInfo();
|
||||
String appName = context.getPackageManager().getApplicationLabel(applicationInfo).toString();
|
||||
switch (type) {
|
||||
case PERMISSION_MICROPHONE: {
|
||||
permission = PermissionRequester.PermissionConstants.MICROPHONE;
|
||||
reasonTitle = context.getString(R.string.tuicalling_permission_mic_reason_title, appName);
|
||||
reason = context.getString(R.string.tuicalling_permission_mic_reason);
|
||||
deniedAlert = context.getString(R.string.tuicalling_tips_start_audio);
|
||||
break;
|
||||
}
|
||||
case PERMISSION_CAMERA: {
|
||||
permission = PermissionRequester.PermissionConstants.CAMERA;
|
||||
reasonTitle = context.getString(R.string.tuicalling_permission_camera_reason_title, appName);
|
||||
reason = context.getString(R.string.tuicalling_permission_camera_reason);
|
||||
deniedAlert = context.getString(R.string.tuicalling_tips_start_camera);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
PermissionRequester.SimpleCallback simpleCallback = new PermissionRequester.SimpleCallback() {
|
||||
@Override
|
||||
public void onGranted() {
|
||||
if (callback != null) {
|
||||
callback.onGranted();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDenied() {
|
||||
if (callback != null) {
|
||||
callback.onDenied();
|
||||
}
|
||||
}
|
||||
};
|
||||
if (!TextUtils.isEmpty(permission)) {
|
||||
PermissionRequester.permission(permission)
|
||||
.reason(reason)
|
||||
.reasonTitle(reasonTitle)
|
||||
.deniedAlert(deniedAlert)
|
||||
.callback(simpleCallback)
|
||||
.permissionDialogCallback(new PermissionRequester.PermissionDialogCallback() {
|
||||
@Override
|
||||
public void onApproved() {
|
||||
if (callback != null) {
|
||||
callback.onDialogApproved();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRefused() {
|
||||
if (callback != null) {
|
||||
callback.onDialogRefused();
|
||||
}
|
||||
}
|
||||
})
|
||||
.request();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class PermissionCallback {
|
||||
|
||||
public void onGranted() {
|
||||
}
|
||||
|
||||
public void onDenied() {
|
||||
}
|
||||
|
||||
public void onDialogApproved() {
|
||||
}
|
||||
|
||||
public void onDialogRefused() {
|
||||
}
|
||||
}
|
||||
|
||||
public static void requestFloatPermission(Context context) {
|
||||
if (PermissionUtils.hasPermission(context)) {
|
||||
return;
|
||||
}
|
||||
if (BrandUtils.isBrandVivo()) {
|
||||
requestVivoFloatPermission(context);
|
||||
} else {
|
||||
startCommonSettings(context);
|
||||
}
|
||||
}
|
||||
|
||||
private static void startCommonSettings(Context context) {
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
|
||||
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
|
||||
intent.setData(Uri.parse("package:" + context.getPackageName()));
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
private static void requestVivoFloatPermission(Context context) {
|
||||
Intent vivoIntent = new Intent();
|
||||
String model = BrandUtils.getModel();
|
||||
boolean isVivoY85 = false;
|
||||
if (!TextUtils.isEmpty(model)) {
|
||||
isVivoY85 = model.contains("Y85") && !model.contains("Y85A");
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(model) && (isVivoY85 || model.contains("vivo Y53L"))) {
|
||||
vivoIntent.setClassName("com.vivo.permissionmanager",
|
||||
"com.vivo.permissionmanager.activity.PurviewTabActivity");
|
||||
vivoIntent.putExtra("tabId", "1");
|
||||
} else {
|
||||
vivoIntent.setClassName("com.vivo.permissionmanager",
|
||||
"com.vivo.permissionmanager.activity.SoftPermissionDetailActivity");
|
||||
vivoIntent.setAction("secure.intent.action.softPermissionDetail");
|
||||
}
|
||||
|
||||
vivoIntent.putExtra("packagename", context.getPackageName());
|
||||
vivoIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(vivoIntent);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.utils;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.tencent.imsdk.v2.V2TIMManager;
|
||||
import com.tencent.imsdk.v2.V2TIMUserFullInfo;
|
||||
import com.tencent.imsdk.v2.V2TIMValueCallback;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.impl.base.TUILog;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.CallingUserModel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class UserInfoUtils {
|
||||
private static final String TAG = "UserInfoUtils";
|
||||
private static final String ERROR_MSG_EMPTY_LIST = "userList is empty";
|
||||
|
||||
public UserInfoUtils() {
|
||||
}
|
||||
|
||||
public void getUserInfo(String userId, final UserCallback callback) {
|
||||
if (TextUtils.isEmpty(userId)) {
|
||||
TUILog.e(TAG, "getUserInfo, userId is empty.");
|
||||
if (callback != null) {
|
||||
callback.onFailed(-1, ERROR_MSG_EMPTY_LIST);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add(userId);
|
||||
internalGetUserInfo(list, callback);
|
||||
}
|
||||
|
||||
public void getUserInfo(List<CallingUserModel> userIdList, final UserCallback callback) {
|
||||
if (null == userIdList || userIdList.isEmpty()) {
|
||||
TUILog.e(TAG, "getUserInfo, userIdList is empty.");
|
||||
if (callback != null) {
|
||||
callback.onFailed(-1, ERROR_MSG_EMPTY_LIST);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> list = new ArrayList<>();
|
||||
for (CallingUserModel model : userIdList) {
|
||||
if (null != model && !TextUtils.isEmpty(model.userId)) {
|
||||
list.add(model.userId);
|
||||
}
|
||||
}
|
||||
internalGetUserInfo(list, callback);
|
||||
}
|
||||
|
||||
private void internalGetUserInfo(List<String> userList, UserCallback callback) {
|
||||
if (null == userList || userList.isEmpty()) {
|
||||
TUILog.e(TAG, "internalGetUserInfo, userIdList is empty.");
|
||||
if (callback != null) {
|
||||
callback.onFailed(-1, ERROR_MSG_EMPTY_LIST);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
V2TIMManager.getInstance().getUsersInfo(userList, new V2TIMValueCallback<List<V2TIMUserFullInfo>>() {
|
||||
@Override
|
||||
public void onError(int errorCode, String errorMsg) {
|
||||
TUILog.e(TAG, "internalGetUserInfo fail, errorCode: " + errorCode + ", errorMsg: " + errorMsg);
|
||||
if (callback != null) {
|
||||
callback.onFailed(errorCode, errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(List<V2TIMUserFullInfo> userFullInfoList) {
|
||||
if (null == userFullInfoList || userFullInfoList.isEmpty()) {
|
||||
TUILog.e(TAG, "internalGetUserInfo result is empty");
|
||||
if (null != callback) {
|
||||
callback.onFailed(-1, ERROR_MSG_EMPTY_LIST);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
List<CallingUserModel> list = new ArrayList<>();
|
||||
for (int i = 0; i < userFullInfoList.size(); i++) {
|
||||
CallingUserModel model = new CallingUserModel();
|
||||
model.userName = userFullInfoList.get(i).getNickName();
|
||||
model.userId = userFullInfoList.get(i).getUserID();
|
||||
model.userAvatar = userFullInfoList.get(i).getFaceUrl();
|
||||
|
||||
if (!isUrl(model.userAvatar)) {
|
||||
model.userAvatar = "";
|
||||
}
|
||||
|
||||
model.userName = TextUtils.isEmpty(model.userName) ? model.userId : model.userName;
|
||||
TUILog.i(TAG, "internalGetUserInfo, model: " + model);
|
||||
list.add(model);
|
||||
}
|
||||
if (callback != null) {
|
||||
callback.onSuccess(list);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isUrl(String url) {
|
||||
return !TextUtils.isEmpty(url) && (url.startsWith("http://") || url.startsWith("https://"));
|
||||
}
|
||||
|
||||
public interface UserCallback {
|
||||
void onSuccess(List<CallingUserModel> list);
|
||||
|
||||
void onFailed(int errorCode, String errorMsg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,888 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.tencent.qcloud.tuicore.TUIConstants;
|
||||
import com.tencent.qcloud.tuicore.TUICore;
|
||||
import com.tencent.qcloud.tuicore.TUILogin;
|
||||
import com.tencent.qcloud.tuicore.interfaces.ITUINotification;
|
||||
import com.tencent.qcloud.tuicore.interfaces.ITUIService;
|
||||
import com.tencent.qcloud.tuicore.util.ToastUtil;
|
||||
import com.tencent.qcloud.tuikit.TUICommonDefine;
|
||||
import com.tencent.qcloud.tuikit.TUIVideoView;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallDefine;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallDefine.MediaType;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallDefine.Role;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallDefine.Scene;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallDefine.Status;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.impl.base.TUILog;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.utils.PermissionUtils;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.R;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.BaseCallActivity;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.CallingUserModel;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.Constants;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.TUICallingAction;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.TUICallingStatusManager;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.UserLayout;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.UserLayoutEntity;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.utils.ImageLoader;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.utils.PermissionRequest;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.utils.UserInfoUtils;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.component.BaseUserView;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.component.TUICallingSingleVideoUserView;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.component.TUICallingUserView;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.floatwindow.FloatCallView;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.floatwindow.FloatWindowService;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.floatwindow.HomeWatcher;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.function.BaseFunctionView;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.function.TUICallingAudioFunctionView;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.function.TUICallingSwitchAudioView;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.function.TUICallingVideoFunctionView;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.function.TUICallingVideoInviteFunctionView;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.function.TUICallingWaitFunctionView;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.root.BaseCallView;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.root.TUICallingGroupView;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.root.TUICallingImageView;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.root.TUICallingSingleView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class TUICallingViewManager implements ITUINotification {
|
||||
private static final String TAG = "TUICallingViewManager";
|
||||
|
||||
private final Context mContext;
|
||||
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
|
||||
private final UserLayoutFactory mUserLayoutFactory;
|
||||
private final TUICallingAction mCallingAction;
|
||||
|
||||
private CallingUserModel mSelfUserModel;
|
||||
private List<CallingUserModel> mInviteeList = new ArrayList<>();
|
||||
private CallingUserModel mInviter;
|
||||
private boolean mEnableFloatView = false;
|
||||
|
||||
private BaseCallView mBaseCallView;
|
||||
private BaseFunctionView mFunctionView;
|
||||
private BaseUserView mUserView;
|
||||
private ImageView mImageFloatFunction;
|
||||
private FloatCallView mFloatCallView;
|
||||
private LinearLayout mOtherUserLayout;
|
||||
private HomeWatcher mHomeWatcher;
|
||||
private UserInfoUtils mUserInfoUtils;
|
||||
|
||||
public TUICallingViewManager(Context context) {
|
||||
mContext = context.getApplicationContext();
|
||||
mUserLayoutFactory = new UserLayoutFactory(mContext);
|
||||
mCallingAction = new TUICallingAction(context);
|
||||
mUserInfoUtils = new UserInfoUtils();
|
||||
registerCallingEvent();
|
||||
}
|
||||
|
||||
private void registerCallingEvent() {
|
||||
TUICore.registerEvent(Constants.EVENT_TUICALLING_CHANGED, Constants.EVENT_SUB_CAMERA_OPEN, this);
|
||||
TUICore.registerEvent(Constants.EVENT_TUICALLING_CHANGED, Constants.EVENT_SUB_MIC_STATUS_CHANGED, this);
|
||||
|
||||
TUICore.registerEvent(Constants.EVENT_TUICALLING_CHANGED, Constants.EVENT_SUB_CALL_STATUS_CHANGED, this);
|
||||
TUICore.registerEvent(Constants.EVENT_TUICALLING_CHANGED, Constants.EVENT_SUB_CALL_TYPE_CHANGED, this);
|
||||
TUICore.registerEvent(TUIConstants.TUIGroup.EVENT_GROUP,
|
||||
TUIConstants.TUIGroup.EVENT_SUB_KEY_GROUP_MEMBER_SELECTED, this);
|
||||
}
|
||||
|
||||
public void createCallingView(List<CallingUserModel> inviteeList, CallingUserModel inviter) {
|
||||
mInviter = inviter;
|
||||
mInviteeList = inviteeList;
|
||||
initHomeWatcher();
|
||||
TUILog.i(TAG, "createCallingView mInviter: " + mInviter + " ,mInviteeList: " + mInviteeList);
|
||||
|
||||
if (Scene.SINGLE_CALL.equals(TUICallingStatusManager.sharedInstance(mContext).getCallScene())) {
|
||||
initSingleWaitingView();
|
||||
} else {
|
||||
initGroupWaitingView();
|
||||
}
|
||||
}
|
||||
|
||||
//JoinInGroupCall
|
||||
public void createGroupCallingAcceptView() {
|
||||
initSelfModel();
|
||||
mUserLayoutFactory.allocUserLayout(mSelfUserModel);
|
||||
initGroupAcceptCallView();
|
||||
}
|
||||
|
||||
public void updateCallingUserView(List<CallingUserModel> inviteeList, CallingUserModel inviter) {
|
||||
mInviter = inviter;
|
||||
mInviteeList = inviteeList;
|
||||
|
||||
CallingUserModel userModel;
|
||||
if (TUICallDefine.Role.Caller.equals(TUICallingStatusManager.sharedInstance(mContext).getCallRole())) {
|
||||
userModel = inviteeList.get(0);
|
||||
for (CallingUserModel model : inviteeList) {
|
||||
reloadUserModel(model);
|
||||
}
|
||||
} else {
|
||||
userModel = inviter;
|
||||
reloadUserModel(inviter);
|
||||
}
|
||||
|
||||
if (null != mUserView) {
|
||||
mUserView.updateUserInfo(userModel);
|
||||
}
|
||||
initOtherInviteeView();
|
||||
}
|
||||
|
||||
public void showCallingView() {
|
||||
TUILog.i(TAG, "showCallingView: mBaseCallView: " + mBaseCallView);
|
||||
BaseCallActivity.updateBaseView(mBaseCallView);
|
||||
Intent intent = new Intent(mContext, BaseCallActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mContext.startActivity(intent);
|
||||
}
|
||||
|
||||
public void closeCallingView() {
|
||||
if (null != mBaseCallView) {
|
||||
mBaseCallView.finish();
|
||||
}
|
||||
mBaseCallView = null;
|
||||
BaseCallActivity.finishActivity();
|
||||
|
||||
mSelfUserModel = null;
|
||||
mInviteeList.clear();
|
||||
mInviter = new CallingUserModel();
|
||||
|
||||
TUICallingStatusManager.sharedInstance(mContext).clear();
|
||||
|
||||
mFunctionView = null;
|
||||
mFloatCallView = null;
|
||||
mUserView = null;
|
||||
mImageFloatFunction = null;
|
||||
mOtherUserLayout = null;
|
||||
|
||||
if (null != mHomeWatcher) {
|
||||
mHomeWatcher.stopWatch();
|
||||
mHomeWatcher = null;
|
||||
}
|
||||
FloatWindowService.stopService(mContext);
|
||||
}
|
||||
|
||||
private void updateCallStatus(TUICallDefine.Status status) {
|
||||
if (TUICallDefine.Status.None.equals(status)) {
|
||||
closeCallingView();
|
||||
return;
|
||||
}
|
||||
if (!TUICallDefine.Status.Accept.equals(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (null != mBaseCallView) {
|
||||
if (Scene.SINGLE_CALL.equals(TUICallingStatusManager.sharedInstance(mContext).getCallScene())) {
|
||||
initSingleAcceptCallView();
|
||||
} else {
|
||||
initGroupAcceptCallView();
|
||||
}
|
||||
}
|
||||
if (null != mFloatCallView) {
|
||||
updateFloatView(TUICallingStatusManager.sharedInstance(mContext).getCallStatus());
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCallType(TUICallDefine.MediaType type) {
|
||||
if (TUICallDefine.MediaType.Unknown.equals(type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mBaseCallView == null) {
|
||||
return;
|
||||
}
|
||||
mBaseCallView.finish();
|
||||
mBaseCallView = null;
|
||||
|
||||
if (TUICallDefine.Status.Waiting.equals(TUICallingStatusManager.sharedInstance(mContext).getCallStatus())) {
|
||||
initSingleWaitingView();
|
||||
} else {
|
||||
initAudioPlayDevice();
|
||||
initSingleAcceptCallView();
|
||||
}
|
||||
|
||||
if (null != mFloatCallView) {
|
||||
updateFloatView(TUICallingStatusManager.sharedInstance(mContext).getCallStatus());
|
||||
}
|
||||
}
|
||||
|
||||
public void userCallingTimeStr(String time) {
|
||||
if (null == mBaseCallView) {
|
||||
return;
|
||||
}
|
||||
mMainHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (null != mFloatCallView) {
|
||||
mFloatCallView.updateCallTimeView(time);
|
||||
}
|
||||
|
||||
if (null != mBaseCallView) {
|
||||
mBaseCallView.updateCallTimeView(time);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void userEnter(CallingUserModel userModel) {
|
||||
if (null == userModel || TextUtils.isEmpty(userModel.userId)) {
|
||||
return;
|
||||
}
|
||||
userModel.isEnter = true;
|
||||
if (!mInviteeList.contains(userModel)) {
|
||||
mInviteeList.add(userModel);
|
||||
}
|
||||
if (null != mBaseCallView) {
|
||||
mBaseCallView.userEnter(userModel);
|
||||
}
|
||||
if (TextUtils.isEmpty(userModel.userName) || TextUtils.isEmpty(userModel.userAvatar)) {
|
||||
loadUserInfo(userModel);
|
||||
}
|
||||
}
|
||||
|
||||
public void userLeave(CallingUserModel userModel) {
|
||||
if (userModel == null || TextUtils.isEmpty(userModel.userId)) {
|
||||
return;
|
||||
}
|
||||
if (mInviter != null && userModel.userId.equals(mInviter.userId)) {
|
||||
mInviter = new CallingUserModel();
|
||||
}
|
||||
mInviteeList.remove(userModel);
|
||||
initOtherInviteeView();
|
||||
|
||||
if (null != mBaseCallView) {
|
||||
mBaseCallView.userLeave(userModel);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateUser(CallingUserModel userModel) {
|
||||
if (null == userModel || TextUtils.isEmpty(userModel.userId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
initSelfModel();
|
||||
if (mSelfUserModel != null && userModel.userId.equals(mSelfUserModel.userId)) {
|
||||
userModel.isVideoAvailable = mSelfUserModel.isVideoAvailable;
|
||||
userModel.isAudioAvailable = mSelfUserModel.isAudioAvailable;
|
||||
}
|
||||
|
||||
if (null != mBaseCallView) {
|
||||
mBaseCallView.updateUserInfo(userModel);
|
||||
}
|
||||
|
||||
if (mFloatCallView != null) {
|
||||
CallingUserModel model = findCallingUserModel(mFloatCallView.getCurrentUser());
|
||||
if (model != null && userModel.userId.equals(model.userId)) {
|
||||
updateFloatView(TUICallingStatusManager.sharedInstance(mContext).getCallStatus());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
UserLayout layout = mUserLayoutFactory.findUserLayout(userModel.userId);
|
||||
if (null != layout) {
|
||||
layout.setAudioVolume(userModel.volume, userModel.isAudioAvailable);
|
||||
}
|
||||
}
|
||||
|
||||
public void enableFloatWindow(boolean enable) {
|
||||
mEnableFloatView = enable;
|
||||
}
|
||||
|
||||
private void initSingleWaitingView() {
|
||||
initSelfModel();
|
||||
initAudioPlayDevice();
|
||||
if (TUICallDefine.MediaType.Video.equals(TUICallingStatusManager.sharedInstance(mContext).getMediaType())) {
|
||||
initSingleVideoWaitingView();
|
||||
} else {
|
||||
initSingleAudioWaitingView();
|
||||
}
|
||||
}
|
||||
|
||||
private void initSingleAudioWaitingView() {
|
||||
mBaseCallView = new TUICallingImageView(mContext);
|
||||
String hint;
|
||||
TUICallDefine.Role callRole = TUICallingStatusManager.sharedInstance(mContext).getCallRole();
|
||||
|
||||
if (TUICallDefine.Role.Caller.equals(callRole)) {
|
||||
hint = mContext.getString(R.string.tuicalling_waiting_accept);
|
||||
mFunctionView = new TUICallingAudioFunctionView(mContext);
|
||||
} else {
|
||||
hint = mContext.getString(R.string.tuicalling_invite_audio_call);
|
||||
mFunctionView = new TUICallingWaitFunctionView(mContext);
|
||||
}
|
||||
|
||||
mUserView = new TUICallingUserView(mContext);
|
||||
if (TUICallDefine.Role.Caller.equals(callRole) && !mInviteeList.isEmpty()) {
|
||||
mUserView.updateUserInfo(mInviteeList.get(0));
|
||||
} else {
|
||||
mUserView.updateUserInfo(mInviter);
|
||||
}
|
||||
mBaseCallView.updateUserView(mUserView);
|
||||
|
||||
mBaseCallView.updateCallingHint(hint);
|
||||
mBaseCallView.updateFunctionView(mFunctionView);
|
||||
|
||||
updateViewColor();
|
||||
initFloatingWindowBtn();
|
||||
BaseCallActivity.updateBaseView(mBaseCallView);
|
||||
}
|
||||
|
||||
private void initSingleVideoWaitingView() {
|
||||
mUserLayoutFactory.allocUserLayout(mSelfUserModel);
|
||||
mBaseCallView = new TUICallingSingleView(mContext, mUserLayoutFactory);
|
||||
String hint = "";
|
||||
if (TUICallDefine.Role.Caller.equals(TUICallingStatusManager.sharedInstance(mContext).getCallRole())) {
|
||||
hint = mContext.getString(R.string.tuicalling_waiting_accept);
|
||||
mFunctionView = new TUICallingVideoInviteFunctionView(mContext);
|
||||
} else {
|
||||
hint = mContext.getString(R.string.tuicalling_invite_video_call);
|
||||
mFunctionView = new TUICallingWaitFunctionView(mContext);
|
||||
}
|
||||
|
||||
mUserView = new TUICallingSingleVideoUserView(mContext, hint);
|
||||
mBaseCallView.updateUserView(mUserView);
|
||||
|
||||
mBaseCallView.updateSwitchAudioView(new TUICallingSwitchAudioView(mContext));
|
||||
|
||||
mFunctionView.setLocalUserLayout(mUserLayoutFactory.findUserLayout(TUILogin.getLoginUser()));
|
||||
mBaseCallView.updateFunctionView(mFunctionView);
|
||||
|
||||
updateViewColor();
|
||||
initFloatingWindowBtn();
|
||||
BaseCallActivity.updateBaseView(mBaseCallView);
|
||||
}
|
||||
|
||||
private void initGroupWaitingView() {
|
||||
initSelfModel();
|
||||
initAudioPlayDevice();
|
||||
|
||||
TUICallDefine.MediaType mediaType = TUICallingStatusManager.sharedInstance(mContext).getMediaType();
|
||||
String hint;
|
||||
if (TUICallDefine.Role.Caller.equals(TUICallingStatusManager.sharedInstance(mContext).getCallRole())) {
|
||||
mUserLayoutFactory.allocUserLayout(mSelfUserModel);
|
||||
for (CallingUserModel model : mInviteeList) {
|
||||
if (null != model && !TextUtils.isEmpty(model.userId)) {
|
||||
mUserLayoutFactory.allocUserLayout(model);
|
||||
}
|
||||
}
|
||||
mBaseCallView = new TUICallingGroupView(mContext, mUserLayoutFactory);
|
||||
hint = mContext.getString(R.string.tuicalling_waiting_accept);
|
||||
mFunctionView = (TUICallDefine.MediaType.Video.equals(mediaType))
|
||||
? new TUICallingVideoFunctionView(mContext) :
|
||||
new TUICallingAudioFunctionView(mContext);
|
||||
initInviteUserFunction();
|
||||
} else {
|
||||
mBaseCallView = new TUICallingImageView(mContext);
|
||||
mUserView = new TUICallingUserView(mContext);
|
||||
mFunctionView = new TUICallingWaitFunctionView(mContext);
|
||||
hint = TUICallDefine.MediaType.Audio.equals(mediaType)
|
||||
? mContext.getString(R.string.tuicalling_invite_audio_call) :
|
||||
mContext.getString(R.string.tuicalling_invite_video_call);
|
||||
|
||||
mBaseCallView.updateUserView(mUserView);
|
||||
mBaseCallView.addOtherUserView(initOtherInviteeView());
|
||||
}
|
||||
mFunctionView.setLocalUserLayout(mUserLayoutFactory.findUserLayout(TUILogin.getLoginUser()));
|
||||
|
||||
mBaseCallView.updateCallingHint(hint);
|
||||
mBaseCallView.updateFunctionView(mFunctionView);
|
||||
|
||||
updateViewColor();
|
||||
initFloatingWindowBtn();
|
||||
}
|
||||
|
||||
private void initSingleAcceptCallView() {
|
||||
if (TUICallDefine.MediaType.Audio.equals(TUICallingStatusManager.sharedInstance(mContext).getMediaType())) {
|
||||
initSingleAudioAcceptCallView();
|
||||
} else {
|
||||
initSingleVideoAcceptCallView();
|
||||
}
|
||||
}
|
||||
|
||||
private void initSingleAudioAcceptCallView() {
|
||||
if (mBaseCallView != null) {
|
||||
mBaseCallView.finish();
|
||||
mBaseCallView = null;
|
||||
}
|
||||
mBaseCallView = new TUICallingImageView(mContext);
|
||||
mFunctionView = new TUICallingAudioFunctionView(mContext);
|
||||
mUserView = new TUICallingUserView(mContext);
|
||||
TUICallDefine.Role role = TUICallingStatusManager.sharedInstance(mContext).getCallRole();
|
||||
if (TUICallDefine.Role.Caller.equals(role) && !mInviteeList.isEmpty()) {
|
||||
mUserView.updateUserInfo(mInviteeList.get(0));
|
||||
} else {
|
||||
mUserView.updateUserInfo(mInviter);
|
||||
}
|
||||
|
||||
mBaseCallView.updateFunctionView(mFunctionView);
|
||||
mBaseCallView.updateUserView(mUserView);
|
||||
mBaseCallView.updateCallingHint("");
|
||||
|
||||
updateViewColor();
|
||||
updateFunctionStatus();
|
||||
initFloatingWindowBtn();
|
||||
BaseCallActivity.updateBaseView(mBaseCallView);
|
||||
}
|
||||
|
||||
private void initSingleVideoAcceptCallView() {
|
||||
if (null == mBaseCallView) {
|
||||
mBaseCallView = new TUICallingSingleView(mContext, mUserLayoutFactory);
|
||||
mBaseCallView.updateSwitchAudioView(new TUICallingSwitchAudioView(mContext));
|
||||
}
|
||||
mFunctionView = new TUICallingVideoFunctionView(mContext);
|
||||
mFunctionView.setLocalUserLayout(mUserLayoutFactory.findUserLayout(TUILogin.getLoginUser()));
|
||||
|
||||
mBaseCallView.updateUserView(null);
|
||||
mBaseCallView.updateFunctionView(mFunctionView);
|
||||
|
||||
updateViewColor();
|
||||
updateFunctionStatus();
|
||||
initFloatingWindowBtn();
|
||||
BaseCallActivity.updateBaseView(mBaseCallView);
|
||||
}
|
||||
|
||||
private void initGroupAcceptCallView() {
|
||||
TUICallDefine.MediaType mediaType = TUICallingStatusManager.sharedInstance(mContext).getMediaType();
|
||||
|
||||
if (TUICallDefine.Role.Caller.equals(TUICallingStatusManager.sharedInstance(mContext).getCallRole())) {
|
||||
if (null == mBaseCallView) {
|
||||
mBaseCallView = new TUICallingGroupView(mContext, mUserLayoutFactory);
|
||||
}
|
||||
if (TUICallDefine.MediaType.Video.equals(mediaType)) {
|
||||
mFunctionView = new TUICallingVideoFunctionView(mContext);
|
||||
mBaseCallView.updateFunctionView(mFunctionView);
|
||||
}
|
||||
} else {
|
||||
if (null != mBaseCallView) {
|
||||
mBaseCallView.finish();
|
||||
}
|
||||
|
||||
mUserLayoutFactory.allocUserLayout(mInviter);
|
||||
for (CallingUserModel model : mInviteeList) {
|
||||
if (null != model && !TextUtils.isEmpty(model.userId)) {
|
||||
mUserLayoutFactory.allocUserLayout(model);
|
||||
}
|
||||
}
|
||||
mBaseCallView = new TUICallingGroupView(mContext, mUserLayoutFactory);
|
||||
mFunctionView = (TUICallDefine.MediaType.Video.equals(mediaType))
|
||||
? new TUICallingVideoFunctionView(mContext)
|
||||
: new TUICallingAudioFunctionView(mContext);
|
||||
mBaseCallView.updateFunctionView(mFunctionView);
|
||||
}
|
||||
mFunctionView.setLocalUserLayout(mUserLayoutFactory.findUserLayout(TUILogin.getLoginUser()));
|
||||
mBaseCallView.updateCallingHint("");
|
||||
|
||||
updateViewColor();
|
||||
updateFunctionStatus();
|
||||
initInviteUserFunction();
|
||||
initFloatingWindowBtn();
|
||||
BaseCallActivity.updateBaseView(mBaseCallView);
|
||||
}
|
||||
|
||||
private View initOtherInviteeView() {
|
||||
if (mOtherUserLayout == null) {
|
||||
mOtherUserLayout = new LinearLayout(mContext);
|
||||
} else {
|
||||
mOtherUserLayout.removeAllViews();
|
||||
}
|
||||
|
||||
List<CallingUserModel> otherInviteeList = mInviteeList;
|
||||
|
||||
int squareWidth = mContext.getResources().getDimensionPixelOffset(R.dimen.tuicalling_small_image_size);
|
||||
int leftMargin = mContext.getResources().getDimensionPixelOffset(R.dimen.tuicalling_small_image_left_margin);
|
||||
|
||||
for (int index = 0; index < otherInviteeList.size(); index++) {
|
||||
final CallingUserModel model = otherInviteeList.get(index);
|
||||
final ImageView imageView = new ImageView(mContext);
|
||||
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(squareWidth, squareWidth);
|
||||
if (index != 0) {
|
||||
layoutParams.leftMargin = leftMargin;
|
||||
}
|
||||
imageView.setLayoutParams(layoutParams);
|
||||
ImageLoader.loadImage(mContext, imageView, model.userAvatar, R.drawable.tuicalling_ic_avatar);
|
||||
mOtherUserLayout.addView(imageView);
|
||||
}
|
||||
return mOtherUserLayout;
|
||||
}
|
||||
|
||||
private void updateViewColor() {
|
||||
TUICallDefine.MediaType mediaType = TUICallingStatusManager.sharedInstance(mContext).getMediaType();
|
||||
int backgroundColor = TUICallDefine.MediaType.Video.equals(mediaType)
|
||||
? mContext.getResources().getColor(R.color.tuicalling_color_video_background)
|
||||
: mContext.getResources().getColor(R.color.tuicalling_color_audio_background);
|
||||
|
||||
int textColor = TUICallDefine.MediaType.Video.equals(mediaType)
|
||||
? mContext.getResources().getColor(R.color.tuicalling_color_white)
|
||||
: mContext.getResources().getColor(R.color.tuicalling_color_black);
|
||||
|
||||
if (null != mBaseCallView) {
|
||||
mBaseCallView.updateBackgroundColor(backgroundColor);
|
||||
mBaseCallView.updateTextColor(textColor);
|
||||
}
|
||||
|
||||
if (null != mUserView) {
|
||||
mUserView.updateTextColor(textColor);
|
||||
}
|
||||
if (null != mFunctionView) {
|
||||
mFunctionView.updateTextColor(textColor);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateFunctionStatus() {
|
||||
TUICallingStatusManager statusManager = TUICallingStatusManager.sharedInstance(mContext);
|
||||
statusManager.updateCameraOpenStatus(statusManager.isCameraOpen(), statusManager.getFrontCamera());
|
||||
mCallingAction.selectAudioPlaybackDevice(statusManager.getAudioPlaybackDevice());
|
||||
if (statusManager.isMicMute()) {
|
||||
mCallingAction.closeMicrophone();
|
||||
} else {
|
||||
mCallingAction.openMicrophone(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void initAudioPlayDevice() {
|
||||
TUICallDefine.MediaType mediaType = TUICallingStatusManager.sharedInstance(mContext).getMediaType();
|
||||
TUICommonDefine.AudioPlaybackDevice device = TUICallDefine.MediaType.Audio.equals(mediaType)
|
||||
? TUICommonDefine.AudioPlaybackDevice.Earpiece : TUICommonDefine.AudioPlaybackDevice.Speakerphone;
|
||||
TUICallingStatusManager.sharedInstance(mContext).updateAudioPlaybackDevice(device);
|
||||
}
|
||||
|
||||
private void initSelfModel() {
|
||||
if (mSelfUserModel != null) {
|
||||
return;
|
||||
}
|
||||
mSelfUserModel = new CallingUserModel();
|
||||
mSelfUserModel.userId = TUILogin.getLoginUser();
|
||||
mSelfUserModel.userAvatar = TUILogin.getFaceUrl();
|
||||
mSelfUserModel.userName = TUILogin.getNickName();
|
||||
}
|
||||
|
||||
private void reloadUserModel(CallingUserModel model) {
|
||||
if (model == null || TextUtils.isEmpty(model.userId)) {
|
||||
return;
|
||||
}
|
||||
UserLayout layout = mUserLayoutFactory.findUserLayout(model.userId);
|
||||
if (null != layout) {
|
||||
layout.setUserName(model.userName);
|
||||
ImageLoader.loadImage(mContext, layout.getAvatarImage(), model.userAvatar, R.drawable.tuicalling_ic_avatar);
|
||||
}
|
||||
}
|
||||
|
||||
private void initFloatingWindowBtn() {
|
||||
if (mBaseCallView == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mEnableFloatView) {
|
||||
mImageFloatFunction = new ImageView(mContext);
|
||||
TUICallDefine.MediaType mediaType = TUICallingStatusManager.sharedInstance(mContext).getMediaType();
|
||||
int resId = TUICallDefine.MediaType.Video.equals(mediaType)
|
||||
? R.drawable.tuicalling_ic_move_back_white : R.drawable.tuicalling_ic_move_back_black;
|
||||
mImageFloatFunction.setBackgroundResource(resId);
|
||||
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
mImageFloatFunction.setLayoutParams(lp);
|
||||
mImageFloatFunction.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
startFloatService();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (mImageFloatFunction != null && mImageFloatFunction.getParent() != null) {
|
||||
((ViewGroup) mImageFloatFunction.getParent()).removeView(mImageFloatFunction);
|
||||
}
|
||||
mBaseCallView.enableFloatView(mImageFloatFunction);
|
||||
}
|
||||
|
||||
private void startFloatService() {
|
||||
if (!mEnableFloatView) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (null != mFloatCallView) {
|
||||
return;
|
||||
}
|
||||
if (PermissionUtils.hasPermission(mContext)) {
|
||||
mFloatCallView = createFloatView();
|
||||
updateFloatView(TUICallingStatusManager.sharedInstance(mContext).getCallStatus());
|
||||
FloatWindowService.startFloatService(mContext, mFloatCallView);
|
||||
BaseCallActivity.finishActivity();
|
||||
} else {
|
||||
PermissionRequest.requestFloatPermission(mContext);
|
||||
}
|
||||
}
|
||||
|
||||
private FloatCallView createFloatView() {
|
||||
FloatCallView floatView = new FloatCallView(mContext, mUserLayoutFactory);
|
||||
floatView.setOnClickListener(new FloatCallView.OnClickListener() {
|
||||
@Override
|
||||
public void onClick() {
|
||||
FloatWindowService.stopService(mContext);
|
||||
mFloatCallView = null;
|
||||
mImageFloatFunction = null;
|
||||
|
||||
MediaType mediaType = TUICallingStatusManager.sharedInstance(mContext).getMediaType();
|
||||
Scene callScene = TUICallingStatusManager.sharedInstance(mContext).getCallScene();
|
||||
if (MediaType.Video.equals(mediaType) && Scene.SINGLE_CALL.equals(callScene)) {
|
||||
|
||||
Role callRole = TUICallingStatusManager.sharedInstance(mContext).getCallRole();
|
||||
CallingUserModel model = (Role.Called.equals(callRole)) ? mInviter : mInviteeList.get(0);
|
||||
Status status = TUICallingStatusManager.sharedInstance(mContext).getCallStatus();
|
||||
|
||||
if (Status.Accept.equals(status)) {
|
||||
resetVideoCloudView(mSelfUserModel);
|
||||
resetVideoCloudView(model);
|
||||
} else {
|
||||
resetVideoCloudView(mSelfUserModel);
|
||||
}
|
||||
}
|
||||
showCallingView();
|
||||
}
|
||||
});
|
||||
return floatView;
|
||||
}
|
||||
|
||||
private void resetVideoCloudView(CallingUserModel model) {
|
||||
UserLayout userLayout = mUserLayoutFactory.findUserLayout(model.userId);
|
||||
if (null == userLayout) {
|
||||
userLayout = mUserLayoutFactory.allocUserLayout(model);
|
||||
}
|
||||
|
||||
TUIVideoView videoView = userLayout.getVideoView();
|
||||
if (videoView != null) {
|
||||
if (null != videoView.getParent()) {
|
||||
((ViewGroup) videoView.getParent()).removeView(videoView);
|
||||
}
|
||||
userLayout.addVideoView(videoView);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateFloatView(TUICallDefine.Status status) {
|
||||
if (null == mFloatCallView) {
|
||||
return;
|
||||
}
|
||||
TUICallDefine.MediaType type = TUICallingStatusManager.sharedInstance(mContext).getMediaType();
|
||||
Scene scene = TUICallingStatusManager.sharedInstance(mContext).getCallScene();
|
||||
|
||||
if (TUICallDefine.MediaType.Video.equals(type) && Scene.SINGLE_CALL.equals(scene)) {
|
||||
mFloatCallView.enableCallingHint(false);
|
||||
String userId;
|
||||
if (TUICallDefine.Status.Waiting.equals(status)) {
|
||||
userId = TUILogin.getLoginUser();
|
||||
} else {
|
||||
TUICallDefine.Role callRole = TUICallingStatusManager.sharedInstance(mContext).getCallRole();
|
||||
userId = (TUICallDefine.Role.Caller.equals(callRole)) ? mInviteeList.get(0).userId : mInviter.userId;
|
||||
}
|
||||
mFloatCallView.updateView(true, userId);
|
||||
} else {
|
||||
mFloatCallView.enableCallingHint(TUICallDefine.Status.Waiting.equals(status));
|
||||
mFloatCallView.updateView(false, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void initHomeWatcher() {
|
||||
if (null == mHomeWatcher) {
|
||||
mHomeWatcher = new HomeWatcher(mContext);
|
||||
}
|
||||
mHomeWatcher.setOnHomePressedListener(new HomeWatcher.OnHomePressedListener() {
|
||||
@Override
|
||||
public void onHomePressed() {
|
||||
if (PermissionUtils.hasPermission(mContext)) {
|
||||
startFloatService();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecentAppsPressed() {
|
||||
if (PermissionUtils.hasPermission(mContext)) {
|
||||
startFloatService();
|
||||
}
|
||||
}
|
||||
});
|
||||
mHomeWatcher.startWatch();
|
||||
}
|
||||
|
||||
private CallingUserModel findCallingUserModel(String userId) {
|
||||
if (TextUtils.isEmpty(userId)) {
|
||||
return null;
|
||||
}
|
||||
for (UserLayoutEntity entity : mUserLayoutFactory.mLayoutEntityList) {
|
||||
if (entity != null && userId.equals(entity.userId)) {
|
||||
return entity.userModel;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void initInviteUserFunction() {
|
||||
// ITUIService service = TUICore.getService(TUIConstants.TUIGroup.SERVICE_NAME);
|
||||
// boolean enableInviteUser = (service != null);
|
||||
//
|
||||
// if (enableInviteUser && mBaseCallView != null) {
|
||||
// Button inviteUserBtn = new Button(mContext);
|
||||
// TUICallDefine.MediaType mediaType = TUICallingStatusManager.sharedInstance(mContext).getMediaType();
|
||||
// int resId = TUICallDefine.MediaType.Video.equals(mediaType)
|
||||
// ? R.drawable.tuicalling_ic_add_user_white : R.drawable.tuicalling_ic_add_user_black;
|
||||
// inviteUserBtn.setBackgroundResource(resId);
|
||||
// inviteUserBtn.setOnClickListener(new View.OnClickListener() {
|
||||
// @Override
|
||||
// public void onClick(View v) {
|
||||
// String groupId = TUICallingStatusManager.sharedInstance(mContext).getGroupId();
|
||||
// if (TextUtils.isEmpty(groupId)) {
|
||||
// ToastUtil.toastShortMessage(mContext.getString(R.string.tuicalling_groupid_is_empty));
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// TUICallDefine.Status status = TUICallingStatusManager.sharedInstance(mContext).getCallStatus();
|
||||
// TUICallDefine.Role role = TUICallingStatusManager.sharedInstance(mContext).getCallRole();
|
||||
// if (TUICallDefine.Role.Called.equals(role) && !TUICallDefine.Status.Accept.equals(status)) {
|
||||
// ToastUtil.toastShortMessage(mContext.getString(R.string.tuicalling_status_is_not_accept));
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// ArrayList<String> list = new ArrayList<>();
|
||||
// list.add(mInviter.userId);
|
||||
// for (CallingUserModel model : mInviteeList) {
|
||||
// if (model != null && !TextUtils.isEmpty(model.userId) && !list.contains(model.userId)) {
|
||||
// list.add(model.userId);
|
||||
// }
|
||||
// }
|
||||
// if (!list.contains(TUILogin.getLoginUser())) {
|
||||
// list.add(TUILogin.getLoginUser());
|
||||
// }
|
||||
//
|
||||
// TUILog.i(TAG, "initInviteUserFunction, groupId: " + groupId + " ,list: " + list);
|
||||
//
|
||||
// Bundle bundle = new Bundle();
|
||||
// bundle.putString(TUIConstants.TUIGroup.GROUP_ID, groupId);
|
||||
// bundle.putString(TUIConstants.TUIGroup.USER_DATA, Constants.TUICALLKIT);
|
||||
// bundle.putStringArrayList(TUIConstants.TUIGroup.SELECTED_LIST, list);
|
||||
// TUICore.startActivity("GroupMemberActivity", bundle);
|
||||
// }
|
||||
// });
|
||||
// mBaseCallView.enableAddUserView(inviteUserBtn);
|
||||
// }
|
||||
}
|
||||
|
||||
private void inviteUsersToGroupCall(List<String> userIdList) {
|
||||
if (userIdList == null || userIdList.isEmpty()) {
|
||||
TUILog.e(TAG, "inviteUsersToGroupCall, userIdList is empty: " + userIdList);
|
||||
return;
|
||||
}
|
||||
|
||||
mCallingAction.inviteUser(userIdList, new TUICommonDefine.ValueCallback() {
|
||||
@Override
|
||||
public void onSuccess(Object data) {
|
||||
if (!(data instanceof List)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> list = (List<String>) data;
|
||||
|
||||
TUILog.i(TAG, "inviteUsersToGroupCall success, list:" + list);
|
||||
for (String userId : list) {
|
||||
if (!TextUtils.isEmpty(userId)) {
|
||||
CallingUserModel userModel = new CallingUserModel();
|
||||
userModel.userId = userId;
|
||||
addUser(userModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errCode, String errMsg) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addUser(CallingUserModel userModel) {
|
||||
if (!mInviteeList.contains(userModel)) {
|
||||
mInviteeList.add(userModel);
|
||||
}
|
||||
if (null != mBaseCallView) {
|
||||
mBaseCallView.userAdd(userModel);
|
||||
}
|
||||
loadUserInfo(userModel);
|
||||
}
|
||||
|
||||
private void loadUserInfo(CallingUserModel model) {
|
||||
UserLayout userLayout = mUserLayoutFactory.allocUserLayout(model);
|
||||
if (userLayout == null) {
|
||||
return;
|
||||
}
|
||||
mUserInfoUtils.getUserInfo(model.userId, new UserInfoUtils.UserCallback() {
|
||||
@Override
|
||||
public void onSuccess(List<CallingUserModel> list) {
|
||||
if (list != null && !list.isEmpty()) {
|
||||
CallingUserModel tempModel = list.get(0);
|
||||
if (tempModel != null && model.userId.equals(tempModel.userId)) {
|
||||
model.userAvatar = tempModel.userAvatar;
|
||||
model.userName = tempModel.userName;
|
||||
}
|
||||
}
|
||||
userLayout.setUserName(model.userName);
|
||||
ImageLoader.loadImage(mContext, userLayout.getAvatarImage(), model.userAvatar,
|
||||
R.drawable.tuicalling_ic_avatar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailed(int errorCode, String errorMsg) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotifyEvent(String key, String subKey, Map<String, Object> param) {
|
||||
if (param == null) {
|
||||
return;
|
||||
}
|
||||
if (Constants.EVENT_TUICALLING_CHANGED.equals(key)) {
|
||||
switch (subKey) {
|
||||
case Constants.EVENT_SUB_CAMERA_OPEN:
|
||||
if (mSelfUserModel != null) {
|
||||
mSelfUserModel.isVideoAvailable = (boolean) param.get(Constants.OPEN_CAMERA);
|
||||
}
|
||||
break;
|
||||
case Constants.EVENT_SUB_MIC_STATUS_CHANGED:
|
||||
if (mSelfUserModel != null) {
|
||||
mSelfUserModel.isAudioAvailable = ((Boolean) param.get(Constants.MUTE_MIC));
|
||||
}
|
||||
UserLayout layout = mUserLayoutFactory.findUserLayout(TUILogin.getLoginUser());
|
||||
if (null != layout) {
|
||||
layout.muteMic(mSelfUserModel.isAudioAvailable);
|
||||
}
|
||||
break;
|
||||
case Constants.EVENT_SUB_CALL_STATUS_CHANGED:
|
||||
updateCallStatus((TUICallDefine.Status) param.get(Constants.CALL_STATUS));
|
||||
break;
|
||||
case Constants.EVENT_SUB_CALL_TYPE_CHANGED:
|
||||
updateCallType((TUICallDefine.MediaType) param.get(Constants.CALL_MEDIA_TYPE));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (TUIConstants.TUIGroup.EVENT_GROUP.equals(key)) {
|
||||
if (TUIConstants.TUIGroup.EVENT_SUB_KEY_GROUP_MEMBER_SELECTED.equals(subKey)) {
|
||||
String userData = (String) param.get(TUIConstants.TUIGroup.USER_DATA);
|
||||
if (!Constants.TUICALLKIT.equals(userData)) {
|
||||
return;
|
||||
}
|
||||
List<String> list = (List<String>) param.get(TUIConstants.TUIGroup.LIST);
|
||||
inviteUsersToGroupCall(list);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.CallingUserModel;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.UserLayout;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.UserLayoutEntity;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class UserLayoutFactory {
|
||||
private Context mContext;
|
||||
public LinkedList<UserLayoutEntity> mLayoutEntityList = new LinkedList<>();
|
||||
|
||||
public UserLayoutFactory(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public UserLayout allocUserLayout(CallingUserModel model) {
|
||||
if (null == model || TextUtils.isEmpty(model.userId)) {
|
||||
return null;
|
||||
}
|
||||
UserLayout userLayout = findUserLayout(model.userId);
|
||||
if (null != userLayout) {
|
||||
return userLayout;
|
||||
}
|
||||
UserLayoutEntity layoutEntity = new UserLayoutEntity();
|
||||
layoutEntity.userId = model.userId;
|
||||
layoutEntity.userModel = model;
|
||||
layoutEntity.layout = new UserLayout(mContext);
|
||||
layoutEntity.layout.setVisibility(View.VISIBLE);
|
||||
mLayoutEntityList.add(layoutEntity);
|
||||
return layoutEntity.layout;
|
||||
}
|
||||
|
||||
public UserLayout findUserLayout(String userId) {
|
||||
if (TextUtils.isEmpty(userId)) {
|
||||
return null;
|
||||
}
|
||||
for (UserLayoutEntity layoutEntity : mLayoutEntityList) {
|
||||
if (userId.equals(layoutEntity.userId)) {
|
||||
return layoutEntity.layout;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.view.component;
|
||||
|
||||
import android.content.Context;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.CallingUserModel;
|
||||
|
||||
public abstract class BaseUserView extends RelativeLayout {
|
||||
public BaseUserView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public void updateUserInfo(CallingUserModel userModel) {
|
||||
}
|
||||
|
||||
public void updateTextColor(int color) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.view.component;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.R;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.CallingUserModel;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.utils.ImageLoader;
|
||||
|
||||
public class TUICallingSingleVideoUserView extends BaseUserView {
|
||||
private Context mContext;
|
||||
private ImageView mImageAvatar;
|
||||
private TextView mTextUserName;
|
||||
private TextView mTextVideoHint;
|
||||
private String mHintMessage;
|
||||
|
||||
public TUICallingSingleVideoUserView(Context context, String message) {
|
||||
super(context);
|
||||
mContext = context.getApplicationContext();
|
||||
mHintMessage = message;
|
||||
initView();
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
LayoutInflater.from(mContext).inflate(R.layout.tuicalling_single_video_user_view, this);
|
||||
mImageAvatar = findViewById(R.id.iv_user_avatar);
|
||||
mTextUserName = findViewById(R.id.tv_user_name);
|
||||
mTextVideoHint = findViewById(R.id.tv_video_tag);
|
||||
mTextVideoHint.setText(mHintMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateUserInfo(CallingUserModel model) {
|
||||
super.updateUserInfo(model);
|
||||
if (null != model && !TextUtils.isEmpty(model.userId)) {
|
||||
ImageLoader.loadImage(mContext, mImageAvatar, model.userAvatar, R.drawable.tuicalling_ic_avatar);
|
||||
mTextUserName.setText(TextUtils.isEmpty(model.userName) ? model.userId : model.userName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.view.component;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.R;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.CallingUserModel;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.utils.ImageLoader;
|
||||
|
||||
public class TUICallingUserView extends BaseUserView {
|
||||
private Context mContext;
|
||||
private ImageView mImageAvatar;
|
||||
private TextView mTextUserName;
|
||||
|
||||
public TUICallingUserView(Context context) {
|
||||
super(context);
|
||||
mContext = context.getApplicationContext();
|
||||
initView();
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
LayoutInflater.from(mContext).inflate(R.layout.tuicalling_user_view, this);
|
||||
mImageAvatar = findViewById(R.id.img_avatar);
|
||||
mTextUserName = findViewById(R.id.tv_name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateUserInfo(CallingUserModel model) {
|
||||
super.updateUserInfo(model);
|
||||
ImageLoader.loadImage(mContext, mImageAvatar, model.userAvatar, R.drawable.tuicalling_ic_avatar);
|
||||
mTextUserName.setText(TextUtils.isEmpty(model.userName) ? model.userId : model.userName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTextColor(int color) {
|
||||
super.updateTextColor(color);
|
||||
mTextUserName.setTextColor(color);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.view.floatwindow;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.tencent.qcloud.tuikit.TUIVideoView;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.R;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.CallingUserModel;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.UserLayout;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.UserLayoutEntity;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.utils.ImageLoader;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.UserLayoutFactory;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class FloatCallView extends RelativeLayout {
|
||||
private static final int UPDATE_COUNT = 3;
|
||||
private static final int UPDATE_INTERVAL = 300;
|
||||
private static final int MESSAGE_LAYOUT_EMPTY = 1;
|
||||
private static final int MESSAGE_VIEW_EMPTY = 2;
|
||||
private int mCount = 0;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
private RelativeLayout mLayoutVideoView;
|
||||
private ImageView mImageAudio;
|
||||
private TextView mTextHint;
|
||||
private TextView mTextTime;
|
||||
private ImageView mImageFloatAvatar;
|
||||
|
||||
private OnClickListener mOnClickListener;
|
||||
private UserLayoutFactory mUserLayoutFactory;
|
||||
private UserLayout mVideoLayout;
|
||||
private String mCurrentUser;
|
||||
private boolean mIsVideoAvailable;
|
||||
|
||||
public FloatCallView(Context context, UserLayoutFactory factory) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
mUserLayoutFactory = factory;
|
||||
initView(context);
|
||||
}
|
||||
|
||||
private void initView(Context context) {
|
||||
LayoutInflater.from(context).inflate(R.layout.tuicalling_floatwindow_layout, this);
|
||||
mLayoutVideoView = findViewById(R.id.rl_video_view);
|
||||
mImageFloatAvatar = findViewById(R.id.img_float_avatar);
|
||||
mTextHint = findViewById(R.id.tv_float_hint);
|
||||
mImageAudio = findViewById(R.id.float_audioView);
|
||||
mTextTime = findViewById(R.id.tv_float_time);
|
||||
setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (null != mOnClickListener) {
|
||||
mOnClickListener.onClick();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void updateView(boolean isVideoAvailable, String userId) {
|
||||
mIsVideoAvailable = isVideoAvailable;
|
||||
if (!isVideoAvailable) {
|
||||
mLayoutVideoView.setVisibility(GONE);
|
||||
mImageFloatAvatar.setVisibility(GONE);
|
||||
mImageAudio.setVisibility(VISIBLE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (null == mUserLayoutFactory || TextUtils.isEmpty(userId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mCurrentUser = userId;
|
||||
mImageAudio.setVisibility(GONE);
|
||||
|
||||
CallingUserModel model = new CallingUserModel();
|
||||
for (UserLayoutEntity entity : mUserLayoutFactory.mLayoutEntityList) {
|
||||
if (entity != null && Objects.equals(entity.userId, userId)) {
|
||||
model = entity.userModel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (model != null && !model.isVideoAvailable) {
|
||||
mLayoutVideoView.removeAllViews();
|
||||
mLayoutVideoView.setVisibility(GONE);
|
||||
mImageFloatAvatar.setVisibility(VISIBLE);
|
||||
ImageLoader.loadImage(mContext, mImageFloatAvatar, model.userAvatar, R.drawable.tuicalling_ic_avatar);
|
||||
return;
|
||||
}
|
||||
mImageFloatAvatar.setVisibility(GONE);
|
||||
|
||||
mVideoLayout = mUserLayoutFactory.findUserLayout(userId);
|
||||
if (null == mVideoLayout) {
|
||||
mViewHandler.sendEmptyMessageDelayed(MESSAGE_LAYOUT_EMPTY, UPDATE_INTERVAL);
|
||||
return;
|
||||
}
|
||||
reloadVideoView();
|
||||
}
|
||||
|
||||
private void reloadVideoView() {
|
||||
if (null == mVideoLayout) {
|
||||
return;
|
||||
}
|
||||
|
||||
TUIVideoView videoView = mVideoLayout.getVideoView();
|
||||
if (videoView == null) {
|
||||
mViewHandler.sendEmptyMessageDelayed(MESSAGE_VIEW_EMPTY, UPDATE_INTERVAL);
|
||||
return;
|
||||
}
|
||||
if (null != videoView.getParent()) {
|
||||
((ViewGroup) videoView.getParent()).removeView(videoView);
|
||||
}
|
||||
mLayoutVideoView.removeAllViews();
|
||||
mLayoutVideoView.setVisibility(VISIBLE);
|
||||
mLayoutVideoView.addView(videoView);
|
||||
}
|
||||
|
||||
private final Handler mViewHandler = new Handler(Looper.getMainLooper()) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
super.handleMessage(msg);
|
||||
if (msg.what == MESSAGE_LAYOUT_EMPTY && null == mVideoLayout && mCount <= UPDATE_COUNT) {
|
||||
mVideoLayout = mUserLayoutFactory.findUserLayout(mCurrentUser);
|
||||
sendEmptyMessageDelayed(MESSAGE_LAYOUT_EMPTY, UPDATE_INTERVAL);
|
||||
mCount++;
|
||||
} else if (msg.what == MESSAGE_VIEW_EMPTY && mCount < UPDATE_COUNT) {
|
||||
sendEmptyMessageDelayed(MESSAGE_VIEW_EMPTY, UPDATE_INTERVAL);
|
||||
mCount++;
|
||||
} else {
|
||||
reloadVideoView();
|
||||
mCount = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public void enableCallingHint(boolean enable) {
|
||||
mTextHint.setVisibility(enable ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
public void updateCallTimeView(String time) {
|
||||
if (mIsVideoAvailable) {
|
||||
mTextTime.setVisibility(GONE);
|
||||
return;
|
||||
}
|
||||
mTextTime.setText(time);
|
||||
mTextTime.setVisibility(TextUtils.isEmpty(time) ? INVISIBLE : VISIBLE);
|
||||
}
|
||||
|
||||
public void setOnClickListener(OnClickListener callback) {
|
||||
mOnClickListener = callback;
|
||||
}
|
||||
|
||||
public String getCurrentUser() {
|
||||
return mCurrentUser;
|
||||
}
|
||||
|
||||
public interface OnClickListener {
|
||||
void onClick();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.view.floatwindow;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.R;
|
||||
|
||||
public class FloatWindowService extends Service {
|
||||
private static Intent mStartIntent;
|
||||
private static FloatCallView mCallView;
|
||||
private static Context mContext;
|
||||
|
||||
private WindowManager mWindowManager;
|
||||
private WindowManager.LayoutParams mWindowLayoutParams;
|
||||
|
||||
private int mScreenWidth;
|
||||
private int mWidth;
|
||||
private int mTouchStartX;
|
||||
private int mTouchStartY;
|
||||
private int mTouchCurrentX;
|
||||
private int mTouchCurrentY;
|
||||
private int mStartX;
|
||||
private int mStartY;
|
||||
private int mStopX;
|
||||
private int mStopY;
|
||||
|
||||
private boolean mIsMove;
|
||||
|
||||
public static void startFloatService(Context context, FloatCallView callView) {
|
||||
mContext = context;
|
||||
mCallView = callView;
|
||||
mStartIntent = new Intent(context, FloatWindowService.class);
|
||||
context.startService(mStartIntent);
|
||||
}
|
||||
|
||||
public static void stopService(Context context) {
|
||||
if (null != mStartIntent) {
|
||||
context.stopService(mStartIntent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
initWindow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return new FloatBinder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
return super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (null != mCallView) {
|
||||
mWindowManager.removeView(mCallView);
|
||||
mCallView = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void initWindow() {
|
||||
mWindowManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
|
||||
mWindowLayoutParams = getViewParams();
|
||||
mScreenWidth = mWindowManager.getDefaultDisplay().getWidth();
|
||||
|
||||
if (null != mCallView) {
|
||||
mCallView.setBackgroundResource(R.drawable.tuicalling_bg_floatwindow_left);
|
||||
mWindowManager.addView(mCallView, mWindowLayoutParams);
|
||||
mCallView.setOnTouchListener(new FloatingListener());
|
||||
}
|
||||
}
|
||||
|
||||
private WindowManager.LayoutParams getViewParams() {
|
||||
mWindowLayoutParams = new WindowManager.LayoutParams();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
mWindowLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||
} else {
|
||||
mWindowLayoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
|
||||
}
|
||||
mWindowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
|
||||
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
||||
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
|
||||
|
||||
mWindowLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
|
||||
mWindowLayoutParams.x = 0;
|
||||
mWindowLayoutParams.y = mWindowManager.getDefaultDisplay().getHeight() / 2;
|
||||
|
||||
mWindowLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||
mWindowLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||
mWindowLayoutParams.format = PixelFormat.TRANSPARENT;
|
||||
|
||||
return mWindowLayoutParams;
|
||||
}
|
||||
|
||||
public class FloatBinder extends Binder {
|
||||
public FloatWindowService getService() {
|
||||
return FloatWindowService.this;
|
||||
}
|
||||
}
|
||||
|
||||
private class FloatingListener implements View.OnTouchListener {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
int action = event.getAction();
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mIsMove = false;
|
||||
mTouchStartX = (int) event.getRawX();
|
||||
mTouchStartY = (int) event.getRawY();
|
||||
|
||||
mStartX = (int) event.getRawX();
|
||||
mStartY = (int) event.getRawY();
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mTouchCurrentX = (int) event.getRawX();
|
||||
mTouchCurrentY = (int) event.getRawY();
|
||||
if (mWindowLayoutParams != null && null != mCallView) {
|
||||
mWindowLayoutParams.x += mTouchCurrentX - mTouchStartX;
|
||||
mWindowLayoutParams.y += mTouchCurrentY - mTouchStartY;
|
||||
mWindowManager.updateViewLayout(mCallView, mWindowLayoutParams);
|
||||
}
|
||||
mTouchStartX = mTouchCurrentX;
|
||||
mTouchStartY = mTouchCurrentY;
|
||||
case MotionEvent.ACTION_UP:
|
||||
mStopX = (int) event.getRawX();
|
||||
mStopY = (int) event.getRawY();
|
||||
if (Math.abs(mStartX - mStopX) >= 5 || Math.abs(mStartY - mStopY) >= 5) {
|
||||
mIsMove = true;
|
||||
if (null != mCallView) {
|
||||
mWidth = mCallView.getWidth();
|
||||
if (mTouchCurrentX > (mScreenWidth / 2)) {
|
||||
startScroll(mStopX, mScreenWidth - mWidth, false);
|
||||
} else {
|
||||
startScroll(mStopX, 0, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return mIsMove;
|
||||
}
|
||||
}
|
||||
|
||||
private void startScroll(int start, int end, boolean isLeft) {
|
||||
ValueAnimator valueAnimator = ValueAnimator.ofFloat(start, end).setDuration(300);
|
||||
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
if (mWindowLayoutParams == null || mCallView == null) {
|
||||
return;
|
||||
}
|
||||
mWidth = mCallView.getWidth();
|
||||
if (isLeft) {
|
||||
mWindowLayoutParams.x = (int) (start * (1 - animation.getAnimatedFraction()));
|
||||
mCallView.setBackgroundResource(R.drawable.tuicalling_bg_floatwindow_left);
|
||||
} else {
|
||||
float end = (mScreenWidth - start - mWidth) * animation.getAnimatedFraction();
|
||||
mWindowLayoutParams.x = (int) (start + end);
|
||||
mCallView.setBackgroundResource(R.drawable.tuicalling_bg_floatwindow_right);
|
||||
}
|
||||
calculateHeight();
|
||||
mWindowManager.updateViewLayout(mCallView, mWindowLayoutParams);
|
||||
}
|
||||
});
|
||||
valueAnimator.start();
|
||||
}
|
||||
|
||||
private void calculateHeight() {
|
||||
if (mWindowLayoutParams == null) {
|
||||
return;
|
||||
}
|
||||
int height = mCallView.getHeight();
|
||||
int screenHeight = mWindowManager.getDefaultDisplay().getHeight();
|
||||
int resourceId = mContext.getResources().getIdentifier("status_bar_height",
|
||||
"dimen", "android");
|
||||
int statusBarHeight = mContext.getResources().getDimensionPixelSize(resourceId);
|
||||
if (mWindowLayoutParams.y < 0) {
|
||||
mWindowLayoutParams.y = 0;
|
||||
} else if (mWindowLayoutParams.y > (screenHeight - height - statusBarHeight)) {
|
||||
mWindowLayoutParams.y = screenHeight - height - statusBarHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.view.floatwindow;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
public class HomeWatcher {
|
||||
private Context mContext;
|
||||
private IntentFilter mFilter;
|
||||
private OnHomePressedListener mListener;
|
||||
private InnerReceiver mReceiver;
|
||||
private boolean mIsRegisted;
|
||||
|
||||
public HomeWatcher(Context context) {
|
||||
mContext = context.getApplicationContext();
|
||||
mFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
|
||||
mReceiver = new InnerReceiver();
|
||||
}
|
||||
|
||||
public void setOnHomePressedListener(OnHomePressedListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
public void startWatch() {
|
||||
if (null != mReceiver && !mIsRegisted) {
|
||||
mContext.registerReceiver(mReceiver, mFilter);
|
||||
mIsRegisted = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void stopWatch() {
|
||||
try {
|
||||
if (null != mReceiver) {
|
||||
mIsRegisted = false;
|
||||
mContext.unregisterReceiver(mReceiver);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
class InnerReceiver extends BroadcastReceiver {
|
||||
private static final String SYSTEM_DIALOG_REASON_KEY = "reason";
|
||||
private static final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
|
||||
private static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
|
||||
private static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (action != null && action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
|
||||
String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
|
||||
if (mListener != null) {
|
||||
if (SYSTEM_DIALOG_REASON_HOME_KEY.equals(reason)) {
|
||||
mListener.onHomePressed();
|
||||
} else if (SYSTEM_DIALOG_REASON_RECENT_APPS.equals(reason)) {
|
||||
mListener.onRecentAppsPressed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnHomePressedListener {
|
||||
void onHomePressed();
|
||||
|
||||
void onRecentAppsPressed();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.view.function;
|
||||
|
||||
import android.content.Context;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import com.tencent.qcloud.tuicore.TUICore;
|
||||
import com.tencent.qcloud.tuicore.interfaces.ITUINotification;
|
||||
import com.tencent.qcloud.tuikit.TUICommonDefine;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.Constants;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.TUICallingAction;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.UserLayout;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class BaseFunctionView extends RelativeLayout {
|
||||
protected Context mContext;
|
||||
protected TUICallingAction mCallingAction;
|
||||
protected UserLayout mLocalUserLayout;
|
||||
|
||||
public BaseFunctionView(Context context) {
|
||||
super(context);
|
||||
mContext = context.getApplicationContext();
|
||||
mCallingAction = new TUICallingAction(context);
|
||||
registerEvent();
|
||||
}
|
||||
|
||||
private void registerEvent() {
|
||||
TUICore.registerEvent(Constants.EVENT_TUICALLING_CHANGED, Constants.EVENT_SUB_CAMERA_OPEN, mNotification);
|
||||
TUICore.registerEvent(Constants.EVENT_TUICALLING_CHANGED, Constants.EVENT_SUB_MIC_STATUS_CHANGED,
|
||||
mNotification);
|
||||
TUICore.registerEvent(Constants.EVENT_TUICALLING_CHANGED, Constants.EVENT_SUB_AUDIOPLAYDEVICE_CHANGED,
|
||||
mNotification);
|
||||
}
|
||||
|
||||
private final ITUINotification mNotification = new ITUINotification() {
|
||||
@Override
|
||||
public void onNotifyEvent(String key, String subKey, Map<String, Object> param) {
|
||||
if (Constants.EVENT_TUICALLING_CHANGED.equals(key) && param != null) {
|
||||
switch (subKey) {
|
||||
case Constants.EVENT_SUB_CAMERA_OPEN:
|
||||
updateCameraOpenStatus((boolean) param.get(Constants.OPEN_CAMERA));
|
||||
break;
|
||||
case Constants.EVENT_SUB_MIC_STATUS_CHANGED:
|
||||
updateMicMuteStatus((Boolean) param.get(Constants.MUTE_MIC));
|
||||
break;
|
||||
case Constants.EVENT_SUB_AUDIOPLAYDEVICE_CHANGED:
|
||||
TUICommonDefine.AudioPlaybackDevice device =
|
||||
(TUICommonDefine.AudioPlaybackDevice) param.get(Constants.HANDS_FREE);
|
||||
updateAudioPlayDevice(TUICommonDefine.AudioPlaybackDevice.Speakerphone.equals(device));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public void updateCameraOpenStatus(boolean isOpen) {
|
||||
}
|
||||
|
||||
public void updateMicMuteStatus(boolean isMicMute) {
|
||||
}
|
||||
|
||||
public void updateAudioPlayDevice(boolean isSpeaker) {
|
||||
}
|
||||
|
||||
public void updateTextColor(int color) {
|
||||
}
|
||||
|
||||
public void setLocalUserLayout(UserLayout layout) {
|
||||
mLocalUserLayout = layout;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.view.function;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.tencent.qcloud.tuicore.util.ToastUtil;
|
||||
import com.tencent.qcloud.tuikit.TUICommonDefine;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.R;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.TUICallingStatusManager;
|
||||
|
||||
public class TUICallingAudioFunctionView extends BaseFunctionView {
|
||||
private LinearLayout mLayoutMute;
|
||||
private LinearLayout mLayoutHangup;
|
||||
private LinearLayout mLayoutHandsFree;
|
||||
private ImageView mImageMute;
|
||||
private ImageView mImageHandsFree;
|
||||
|
||||
public TUICallingAudioFunctionView(Context context) {
|
||||
super(context);
|
||||
initView();
|
||||
initListener();
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
LayoutInflater.from(mContext).inflate(R.layout.tuicalling_funcation_view_audio, this);
|
||||
mLayoutMute = findViewById(R.id.ll_mute);
|
||||
mImageMute = findViewById(R.id.img_mute);
|
||||
mLayoutHangup = findViewById(R.id.ll_hangup);
|
||||
mLayoutHandsFree = findViewById(R.id.ll_handsfree);
|
||||
mImageHandsFree = findViewById(R.id.img_handsfree);
|
||||
}
|
||||
|
||||
private void initListener() {
|
||||
mLayoutMute.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
boolean isMicMute = TUICallingStatusManager.sharedInstance(mContext).isMicMute();
|
||||
if (isMicMute) {
|
||||
mCallingAction.openMicrophone(new TUICommonDefine.Callback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errCode, String errMsg) {
|
||||
|
||||
}
|
||||
});
|
||||
} else {
|
||||
mCallingAction.closeMicrophone();
|
||||
}
|
||||
int resId = isMicMute ? R.string.tuicalling_toast_disable_mute : R.string.tuicalling_toast_enable_mute;
|
||||
ToastUtil.toastShortMessage(mContext.getString(resId));
|
||||
}
|
||||
});
|
||||
mLayoutHangup.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mCallingAction.hangup(null);
|
||||
}
|
||||
});
|
||||
|
||||
mLayoutHandsFree.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
boolean isSpeaker = TUICommonDefine.AudioPlaybackDevice.Speakerphone
|
||||
.equals(TUICallingStatusManager.sharedInstance(mContext).getAudioPlaybackDevice());
|
||||
if (isSpeaker) {
|
||||
mCallingAction.selectAudioPlaybackDevice(TUICommonDefine.AudioPlaybackDevice.Earpiece);
|
||||
} else {
|
||||
mCallingAction.selectAudioPlaybackDevice(TUICommonDefine.AudioPlaybackDevice.Speakerphone);
|
||||
}
|
||||
int resId = isSpeaker ? R.string.tuicalling_toast_use_handset : R.string.tuicalling_toast_speaker;
|
||||
ToastUtil.toastShortMessage(mContext.getString(resId));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMicMuteStatus(boolean isMicMute) {
|
||||
super.updateMicMuteStatus(isMicMute);
|
||||
mImageMute.setActivated(isMicMute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAudioPlayDevice(boolean isSpeaker) {
|
||||
super.updateAudioPlayDevice(isSpeaker);
|
||||
mImageHandsFree.setActivated(isSpeaker);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.view.function;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallDefine;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.R;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.TUICallingAction;
|
||||
|
||||
public class TUICallingSwitchAudioView extends BaseFunctionView {
|
||||
private final Context mContext;
|
||||
|
||||
public TUICallingSwitchAudioView(Context context) {
|
||||
super(context);
|
||||
mContext = context.getApplicationContext();
|
||||
initView();
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
LayoutInflater.from(mContext).inflate(R.layout.tuicalling_switch_audio_view, this);
|
||||
LinearLayout layoutSwitchToAudio = findViewById(R.id.ll_switch_audio);
|
||||
layoutSwitchToAudio.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
TUICallingAction callingAction = new TUICallingAction(mContext);
|
||||
callingAction.switchCallMediaType(TUICallDefine.MediaType.Audio);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.view.function;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.tencent.qcloud.tuicore.TUILogin;
|
||||
import com.tencent.qcloud.tuicore.util.ToastUtil;
|
||||
import com.tencent.qcloud.tuikit.TUICommonDefine;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.R;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.TUICallingStatusManager;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.utils.ImageLoader;
|
||||
|
||||
public class TUICallingVideoFunctionView extends BaseFunctionView {
|
||||
private LinearLayout mLayoutOpenCamera;
|
||||
private LinearLayout mLayoutMute;
|
||||
private LinearLayout mLayoutHandsFree;
|
||||
private LinearLayout mLayoutHangup;
|
||||
private ImageView mImageOpenCamera;
|
||||
private ImageView mImageMute;
|
||||
private ImageView mImageHandsFree;
|
||||
private ImageView mImageSwitchCamera;
|
||||
|
||||
public TUICallingVideoFunctionView(Context context) {
|
||||
super(context);
|
||||
initView();
|
||||
initClickListener();
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
LayoutInflater.from(mContext).inflate(R.layout.tuicalling_funcation_view_video, this);
|
||||
mLayoutMute = (LinearLayout) findViewById(R.id.ll_mute);
|
||||
mImageMute = (ImageView) findViewById(R.id.iv_mute);
|
||||
mLayoutHandsFree = (LinearLayout) findViewById(R.id.ll_handsfree);
|
||||
mImageHandsFree = (ImageView) findViewById(R.id.iv_handsfree);
|
||||
mLayoutOpenCamera = (LinearLayout) findViewById(R.id.ll_open_camera);
|
||||
mImageOpenCamera = (ImageView) findViewById(R.id.img_camera);
|
||||
mLayoutHangup = (LinearLayout) findViewById(R.id.ll_hangup);
|
||||
mImageSwitchCamera = (ImageView) findViewById(R.id.switch_camera);
|
||||
}
|
||||
|
||||
private void initClickListener() {
|
||||
mLayoutMute.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
boolean isMicMute = TUICallingStatusManager.sharedInstance(mContext).isMicMute();
|
||||
if (isMicMute) {
|
||||
mCallingAction.openMicrophone(new TUICommonDefine.Callback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int errCode, String errMsg) {
|
||||
|
||||
}
|
||||
});
|
||||
} else {
|
||||
mCallingAction.closeMicrophone();
|
||||
}
|
||||
int resId = isMicMute ? R.string.tuicalling_toast_disable_mute : R.string.tuicalling_toast_enable_mute;
|
||||
ToastUtil.toastShortMessage(mContext.getString(resId));
|
||||
}
|
||||
});
|
||||
mLayoutHandsFree.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
boolean isSpeaker = TUICommonDefine.AudioPlaybackDevice.Speakerphone
|
||||
.equals(TUICallingStatusManager.sharedInstance(mContext).getAudioPlaybackDevice());
|
||||
if (isSpeaker) {
|
||||
mCallingAction.selectAudioPlaybackDevice(TUICommonDefine.AudioPlaybackDevice.Earpiece);
|
||||
} else {
|
||||
mCallingAction.selectAudioPlaybackDevice(TUICommonDefine.AudioPlaybackDevice.Speakerphone);
|
||||
}
|
||||
int resId = isSpeaker ? R.string.tuicalling_toast_use_handset : R.string.tuicalling_toast_speaker;
|
||||
ToastUtil.toastShortMessage(mContext.getString(resId));
|
||||
}
|
||||
});
|
||||
mLayoutOpenCamera.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (TUICallingStatusManager.sharedInstance(mContext).isCameraOpen()) {
|
||||
mCallingAction.closeCamera();
|
||||
if (null != mLocalUserLayout) {
|
||||
mLocalUserLayout.setVideoAvailable(false);
|
||||
ImageLoader.loadImage(mContext, mLocalUserLayout.getAvatarImage(), TUILogin.getFaceUrl(),
|
||||
R.drawable.tuicalling_ic_avatar);
|
||||
}
|
||||
ToastUtil.toastShortMessage(mContext.getString(R.string.tuicalling_toast_disable_camera));
|
||||
} else {
|
||||
if (null != mLocalUserLayout) {
|
||||
mCallingAction.openCamera(TUICallingStatusManager.sharedInstance(mContext).getFrontCamera(),
|
||||
mLocalUserLayout.getVideoView(), null);
|
||||
mLocalUserLayout.setVideoAvailable(true);
|
||||
ToastUtil.toastShortMessage(mContext.getString(R.string.tuicalling_toast_enable_camera));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mImageSwitchCamera.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
TUICommonDefine.Camera camera = TUICallingStatusManager.sharedInstance(mContext).getFrontCamera();
|
||||
mCallingAction.switchCamera(TUICommonDefine.Camera.Front.equals(camera)
|
||||
? TUICommonDefine.Camera.Back : TUICommonDefine.Camera.Front);
|
||||
ToastUtil.toastShortMessage(mContext.getString(R.string.tuicalling_toast_switch_camera));
|
||||
}
|
||||
});
|
||||
|
||||
mLayoutHangup.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mCallingAction.hangup(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCameraOpenStatus(boolean isOpen) {
|
||||
super.updateCameraOpenStatus(isOpen);
|
||||
mImageOpenCamera.setActivated(isOpen);
|
||||
if (null != mLocalUserLayout) {
|
||||
mLocalUserLayout.setVideoAvailable(isOpen);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMicMuteStatus(boolean isMicMute) {
|
||||
super.updateMicMuteStatus(isMicMute);
|
||||
mImageMute.setActivated(isMicMute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAudioPlayDevice(boolean isSpeaker) {
|
||||
super.updateAudioPlayDevice(isSpeaker);
|
||||
mImageHandsFree.setActivated(isSpeaker);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.view.function;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.tencent.qcloud.tuicore.util.ToastUtil;
|
||||
import com.tencent.qcloud.tuikit.TUICommonDefine;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.R;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.TUICallingStatusManager;
|
||||
|
||||
public class TUICallingVideoInviteFunctionView extends BaseFunctionView {
|
||||
private LinearLayout mLayoutCancel;
|
||||
private ImageView mImageSwitchCamera;
|
||||
|
||||
public TUICallingVideoInviteFunctionView(Context context) {
|
||||
super(context);
|
||||
initView();
|
||||
initClickListener();
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
LayoutInflater.from(mContext).inflate(R.layout.tuicalling_funcation_view_video_inviting, this);
|
||||
mLayoutCancel = findViewById(R.id.ll_cancel);
|
||||
mImageSwitchCamera = findViewById(R.id.img_switch_camera);
|
||||
}
|
||||
|
||||
private void initClickListener() {
|
||||
mLayoutCancel.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mCallingAction.hangup(null);
|
||||
}
|
||||
});
|
||||
|
||||
mImageSwitchCamera.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
TUICommonDefine.Camera camera = TUICallingStatusManager.sharedInstance(mContext).getFrontCamera();
|
||||
mCallingAction.switchCamera(TUICommonDefine.Camera.Front.equals(camera)
|
||||
? TUICommonDefine.Camera.Back : TUICommonDefine.Camera.Front);
|
||||
ToastUtil.toastShortMessage(mContext.getString(R.string.tuicalling_toast_switch_camera));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.view.function;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.R;
|
||||
|
||||
public class TUICallingWaitFunctionView extends BaseFunctionView {
|
||||
private LinearLayout mLayoutReject;
|
||||
private LinearLayout mLayoutDialing;
|
||||
private TextView mTextReject;
|
||||
private TextView mTextDialing;
|
||||
|
||||
public TUICallingWaitFunctionView(Context context) {
|
||||
super(context);
|
||||
initView();
|
||||
initListener();
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
LayoutInflater.from(mContext).inflate(R.layout.tuicalling_funcation_view_audio_waiting, this);
|
||||
mLayoutReject = findViewById(R.id.ll_decline);
|
||||
mLayoutDialing = findViewById(R.id.ll_answer);
|
||||
mTextReject = findViewById(R.id.tv_reject);
|
||||
mTextDialing = findViewById(R.id.tv_dialing);
|
||||
}
|
||||
|
||||
private void initListener() {
|
||||
mLayoutReject.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mCallingAction.reject(null);
|
||||
}
|
||||
});
|
||||
|
||||
mLayoutDialing.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mCallingAction.accept(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTextColor(int color) {
|
||||
mTextReject.setTextColor(color);
|
||||
mTextDialing.setTextColor(color);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.view.root;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.CallingUserModel;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.TUICallingAction;
|
||||
|
||||
public abstract class BaseCallView extends RelativeLayout {
|
||||
protected Context mContext;
|
||||
protected TUICallingAction mCallingAction;
|
||||
|
||||
public BaseCallView(Context context) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
mCallingAction = new TUICallingAction(context);
|
||||
}
|
||||
|
||||
public void userEnter(CallingUserModel userModel) {
|
||||
}
|
||||
|
||||
public void userAdd(CallingUserModel userModel) {
|
||||
}
|
||||
|
||||
public void userLeave(CallingUserModel userModel) {
|
||||
}
|
||||
|
||||
public void updateUserInfo(CallingUserModel userModel) {
|
||||
}
|
||||
|
||||
public void updateCallingHint(String hint) {
|
||||
}
|
||||
|
||||
public void updateCallTimeView(String time) {
|
||||
}
|
||||
|
||||
public void updateUserView(View view) {
|
||||
}
|
||||
|
||||
public void updateFunctionView(View view) {
|
||||
}
|
||||
|
||||
public void updateSwitchAudioView(View view) {
|
||||
}
|
||||
|
||||
public void addOtherUserView(View view) {
|
||||
}
|
||||
|
||||
public void enableFloatView(View view) {
|
||||
}
|
||||
|
||||
public void enableAddUserView(View view) {
|
||||
}
|
||||
|
||||
public void updateBackgroundColor(int color) {
|
||||
}
|
||||
|
||||
public void updateTextColor(int color) {
|
||||
}
|
||||
|
||||
public void finish() {
|
||||
clearAllViews();
|
||||
removeAllViews();
|
||||
detachAllViewsFromParent();
|
||||
onDetachedFromWindow();
|
||||
}
|
||||
|
||||
public void clearAllViews() {
|
||||
updateCallingHint("");
|
||||
updateCallTimeView(null);
|
||||
updateUserView(null);
|
||||
updateFunctionView(null);
|
||||
updateSwitchAudioView(null);
|
||||
addOtherUserView(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.view.root;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.tencent.qcloud.tuicore.TUILogin;
|
||||
import com.tencent.qcloud.tuikit.TUICommonDefine;
|
||||
import com.tencent.qcloud.tuikit.tuicallengine.TUICallDefine;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.R;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.CallingUserModel;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.Constants;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.TUICallingStatusManager;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.UserLayout;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.UserLayoutEntity;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.utils.DeviceUtils;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.utils.DisplayUtils;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.utils.ImageLoader;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.UserLayoutFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class TUICallingGroupView extends BaseCallView {
|
||||
private TextView mTextCallHint;
|
||||
private RelativeLayout mLayoutFunction;
|
||||
private TextView mTextTime;
|
||||
private UserLayoutFactory mUserLayoutFactory;
|
||||
private View mRootView;
|
||||
private RelativeLayout mLayoutFloatView;
|
||||
private RelativeLayout mLayoutAddUserView;
|
||||
private RelativeLayout mLayoutGroupManager;
|
||||
|
||||
private int mCount = 0;
|
||||
private boolean mInitParam = false;
|
||||
|
||||
private ArrayList<LayoutParams> mGrid1ParamList;
|
||||
private ArrayList<LayoutParams> mGrid2ParamList;
|
||||
private ArrayList<LayoutParams> mGrid3ParamList;
|
||||
private ArrayList<LayoutParams> mGrid4ParamList;
|
||||
private ArrayList<LayoutParams> mGrid9ParamList;
|
||||
|
||||
public TUICallingGroupView(Context context, UserLayoutFactory factory) {
|
||||
super(context);
|
||||
mUserLayoutFactory = factory;
|
||||
initView();
|
||||
initData();
|
||||
}
|
||||
|
||||
public void initView() {
|
||||
mRootView = LayoutInflater.from(mContext).inflate(R.layout.tuicalling_background_group_view, this);
|
||||
mLayoutGroupManager = findViewById(R.id.group_layout_manager);
|
||||
mLayoutFloatView = findViewById(R.id.rl_float_view);
|
||||
mLayoutAddUserView = findViewById(R.id.rl_add_user_view);
|
||||
mTextCallHint = findViewById(R.id.tv_group_call_hint);
|
||||
mTextTime = findViewById(R.id.tv_group_time);
|
||||
mLayoutFunction = findViewById(R.id.rl_group_function);
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
for (UserLayoutEntity entity : mUserLayoutFactory.mLayoutEntityList) {
|
||||
if (null == entity || TextUtils.isEmpty(entity.userId)) {
|
||||
continue;
|
||||
}
|
||||
UserLayout layout = allocUserLayout(entity.userModel);
|
||||
TUICallDefine.MediaType mediaType = TUICallingStatusManager.sharedInstance(mContext).getMediaType();
|
||||
if (entity.userId.equals(TUILogin.getLoginUser())) {
|
||||
if (TUICallDefine.MediaType.Video.equals(mediaType)) {
|
||||
layout.setVideoAvailable(true);
|
||||
TUICommonDefine.Camera camera = TUICallingStatusManager.sharedInstance(mContext).getFrontCamera();
|
||||
mCallingAction.openCamera(camera, layout.getVideoView(), null);
|
||||
} else {
|
||||
ImageLoader.loadImage(mContext, entity.layout.getAvatarImage(), TUILogin.getFaceUrl(),
|
||||
R.drawable.tuicalling_ic_avatar);
|
||||
entity.layout.setUserName(TUILogin.getNickName());
|
||||
}
|
||||
} else {
|
||||
if (null != entity.userModel) {
|
||||
if (TUICallDefine.MediaType.Video.equals(mediaType) && entity.userModel.isVideoAvailable) {
|
||||
layout.setVideoAvailable(true);
|
||||
mCallingAction.startRemoteView(entity.userId, layout.getVideoView(),
|
||||
new TUICommonDefine.PlayCallback() {
|
||||
@Override
|
||||
public void onPlaying(String userId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoading(String userId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String userId, int errCode, String errMsg) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
ImageLoader.loadImage(mContext, entity.layout.getAvatarImage(), entity.userModel.userAvatar,
|
||||
R.drawable.tuicalling_ic_avatar);
|
||||
entity.layout.setUserName(entity.userModel.userName);
|
||||
if (entity.userModel.isEnter) {
|
||||
entity.layout.stopLoading();
|
||||
} else {
|
||||
entity.layout.startLoading();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userEnter(CallingUserModel userModel) {
|
||||
super.userEnter(userModel);
|
||||
UserLayout layout = mUserLayoutFactory.findUserLayout(userModel.userId);
|
||||
if (null == layout) {
|
||||
layout = allocUserLayout(userModel);
|
||||
}
|
||||
if (layout == null) {
|
||||
return;
|
||||
}
|
||||
layout.stopLoading();
|
||||
TUICallDefine.MediaType mediaType = TUICallingStatusManager.sharedInstance(mContext).getMediaType();
|
||||
if (TUICallDefine.MediaType.Video.equals(mediaType)) {
|
||||
layout.setVideoAvailable(true);
|
||||
mCallingAction.startRemoteView(userModel.userId, layout.getVideoView(),
|
||||
new TUICommonDefine.PlayCallback() {
|
||||
@Override
|
||||
public void onPlaying(String userId) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoading(String userId) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String userId, int errCode, String errMsg) {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userAdd(CallingUserModel userModel) {
|
||||
super.userAdd(userModel);
|
||||
UserLayout layout = mUserLayoutFactory.findUserLayout(userModel.userId);
|
||||
if (null == layout) {
|
||||
layout = allocUserLayout(userModel);
|
||||
}
|
||||
if (layout == null) {
|
||||
return;
|
||||
}
|
||||
layout.startLoading();
|
||||
TUICallDefine.MediaType mediaType = TUICallingStatusManager.sharedInstance(mContext).getMediaType();
|
||||
if (TUICallDefine.MediaType.Video.equals(mediaType)) {
|
||||
mCallingAction.startRemoteView(userModel.userId, layout.getVideoView(),
|
||||
new TUICommonDefine.PlayCallback() {
|
||||
@Override
|
||||
public void onPlaying(String userId) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoading(String userId) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String userId, int errCode, String errMsg) {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userLeave(CallingUserModel userModel) {
|
||||
super.userLeave(userModel);
|
||||
if (null != userModel) {
|
||||
recyclerUserLayout(userModel.userId);
|
||||
mCallingAction.stopRemoteView(userModel.userId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateUserInfo(CallingUserModel userModel) {
|
||||
super.updateUserInfo(userModel);
|
||||
UserLayout userLayout = mUserLayoutFactory.findUserLayout(userModel.userId);
|
||||
if (null != userLayout) {
|
||||
userLayout.setVideoAvailable(userModel.isVideoAvailable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCallingHint(String hint) {
|
||||
super.updateCallingHint(hint);
|
||||
mTextCallHint.setText(hint);
|
||||
mTextCallHint.setVisibility(TextUtils.isEmpty(hint) ? GONE : VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCallTimeView(String time) {
|
||||
mTextTime.setText(time);
|
||||
mTextTime.setVisibility(TextUtils.isEmpty(time) ? GONE : VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFunctionView(View view) {
|
||||
mLayoutFunction.removeAllViews();
|
||||
if (null != view) {
|
||||
mLayoutFunction.addView(view);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBackgroundColor(int color) {
|
||||
mRootView.setBackgroundColor(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTextColor(int color) {
|
||||
super.updateTextColor(color);
|
||||
mTextCallHint.setTextColor(color);
|
||||
mTextTime.setTextColor(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableFloatView(View view) {
|
||||
mLayoutFloatView.removeAllViews();
|
||||
if (null != view) {
|
||||
mLayoutFloatView.addView(view);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableAddUserView(View view) {
|
||||
mLayoutAddUserView.removeAllViews();
|
||||
if (null != view) {
|
||||
mLayoutAddUserView.addView(view);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
if (null != mLayoutGroupManager) {
|
||||
recyclerAllUserLayout();
|
||||
}
|
||||
super.finish();
|
||||
}
|
||||
|
||||
private UserLayout allocUserLayout(CallingUserModel userModel) {
|
||||
if (null == userModel || TextUtils.isEmpty(userModel.userId)) {
|
||||
return null;
|
||||
}
|
||||
if (mCount > Constants.MAX_USER) {
|
||||
return null;
|
||||
}
|
||||
UserLayout userLayout = mUserLayoutFactory.allocUserLayout(userModel);
|
||||
if (null != userLayout.getParent()) {
|
||||
((ViewGroup) userLayout.getParent()).removeView(userLayout);
|
||||
}
|
||||
mLayoutGroupManager.addView(userLayout);
|
||||
mCount++;
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
makeGirdLayout(true);
|
||||
}
|
||||
});
|
||||
return userLayout;
|
||||
}
|
||||
|
||||
private void recyclerUserLayout(String userId) {
|
||||
if (TextUtils.isEmpty(userId)) {
|
||||
return;
|
||||
}
|
||||
Iterator iterator = mUserLayoutFactory.mLayoutEntityList.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
UserLayoutEntity item = (UserLayoutEntity) iterator.next();
|
||||
if (userId.equals(item.userId)) {
|
||||
mLayoutGroupManager.removeView(item.layout);
|
||||
iterator.remove();
|
||||
mCount--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
makeGirdLayout(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void recyclerAllUserLayout() {
|
||||
if (null == mUserLayoutFactory) {
|
||||
return;
|
||||
}
|
||||
Iterator iterator = mUserLayoutFactory.mLayoutEntityList.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
UserLayoutEntity item = (UserLayoutEntity) iterator.next();
|
||||
mLayoutGroupManager.removeView(item.layout);
|
||||
iterator.remove();
|
||||
}
|
||||
mCount = 0;
|
||||
}
|
||||
|
||||
private void makeGirdLayout(boolean needUpdate) {
|
||||
if (!mInitParam) {
|
||||
int width = DeviceUtils.getScreenWidth(mContext);
|
||||
int height = DeviceUtils.getScreenHeight(mContext);
|
||||
int size = Math.min(width, height);
|
||||
mGrid1ParamList = DisplayUtils.initGrid1Param(getContext(), size, size);
|
||||
mGrid2ParamList = DisplayUtils.initGrid2Param(getContext(), size, size);
|
||||
mGrid3ParamList = DisplayUtils.initGrid3Param(getContext(), size, size);
|
||||
mGrid4ParamList = DisplayUtils.initGrid4Param(getContext(), size, size);
|
||||
mGrid9ParamList = DisplayUtils.initGrid9Param(getContext(), size, size);
|
||||
mInitParam = true;
|
||||
}
|
||||
if (null == mUserLayoutFactory || mUserLayoutFactory.mLayoutEntityList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (needUpdate) {
|
||||
ArrayList<LayoutParams> paramList;
|
||||
if (mCount <= 1) {
|
||||
paramList = mGrid1ParamList;
|
||||
UserLayoutEntity entity = mUserLayoutFactory.mLayoutEntityList.get(0);
|
||||
entity.layout.setLayoutParams(paramList.get(0));
|
||||
return;
|
||||
} else if (mCount == 2) {
|
||||
paramList = mGrid2ParamList;
|
||||
} else if (mCount == 3) {
|
||||
paramList = mGrid3ParamList;
|
||||
} else if (mCount == 4) {
|
||||
paramList = mGrid4ParamList;
|
||||
} else {
|
||||
paramList = mGrid9ParamList;
|
||||
}
|
||||
int layoutIndex = TextUtils.isEmpty(TUILogin.getLoginUser()) ? 0 : 1;
|
||||
for (int i = 0; i < mUserLayoutFactory.mLayoutEntityList.size(); i++) {
|
||||
UserLayoutEntity entity = mUserLayoutFactory.mLayoutEntityList.get(i);
|
||||
if (entity.userId.equals(TUILogin.getLoginUser())) {
|
||||
entity.layout.setLayoutParams(paramList.get(0));
|
||||
} else if (layoutIndex < paramList.size()) {
|
||||
entity.layout.setLayoutParams(paramList.get(layoutIndex++));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.view.root;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.R;
|
||||
|
||||
public class TUICallingImageView extends BaseCallView {
|
||||
private Context mContext;
|
||||
private RelativeLayout mLayoutUserView;
|
||||
private LinearLayout mLayoutOtherUserContainer;
|
||||
private RelativeLayout mLayoutFunction;
|
||||
private TextView mTextTime;
|
||||
private TextView mTextCallHint;
|
||||
private View mRootView;
|
||||
private RelativeLayout mLayoutFloatView;
|
||||
private RelativeLayout mLayoutAddUserView;
|
||||
|
||||
public TUICallingImageView(Context context) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
initView();
|
||||
}
|
||||
|
||||
public void initView() {
|
||||
mRootView = LayoutInflater.from(mContext).inflate(R.layout.tuicalling_background_image_view, this);
|
||||
mLayoutFloatView = findViewById(R.id.rl_float_view);
|
||||
mLayoutAddUserView = findViewById(R.id.rl_add_user_view);
|
||||
mLayoutUserView = findViewById(R.id.rl_single_audio_view);
|
||||
mTextCallHint = findViewById(R.id.tv_call_hint);
|
||||
mLayoutOtherUserContainer = findViewById(R.id.ll_other_user_container);
|
||||
mTextTime = findViewById(R.id.tv_image_time);
|
||||
mLayoutFunction = findViewById(R.id.rl_image_function);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateUserView(View view) {
|
||||
super.updateUserView(view);
|
||||
mLayoutUserView.removeAllViews();
|
||||
if (null != view) {
|
||||
mLayoutUserView.addView(view);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOtherUserView(View view) {
|
||||
super.addOtherUserView(view);
|
||||
mLayoutOtherUserContainer.removeAllViews();
|
||||
if (null != view) {
|
||||
mLayoutOtherUserContainer.addView(view);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCallingHint(String hint) {
|
||||
super.updateCallingHint(hint);
|
||||
mTextCallHint.setText(hint);
|
||||
mTextCallHint.setVisibility(TextUtils.isEmpty(hint) ? GONE : VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCallTimeView(String time) {
|
||||
mTextTime.setText(time);
|
||||
mTextTime.setVisibility(TextUtils.isEmpty(time) ? GONE : VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFunctionView(View view) {
|
||||
mLayoutFunction.removeAllViews();
|
||||
if (null != view) {
|
||||
mLayoutFunction.addView(view);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBackgroundColor(int color) {
|
||||
mRootView.setBackgroundColor(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTextColor(int color) {
|
||||
super.updateTextColor(color);
|
||||
mTextCallHint.setTextColor(color);
|
||||
mTextTime.setTextColor(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableFloatView(View view) {
|
||||
mLayoutFloatView.removeAllViews();
|
||||
if (null != view) {
|
||||
mLayoutFloatView.addView(view);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableAddUserView(View view) {
|
||||
mLayoutAddUserView.removeAllViews();
|
||||
if (null != view) {
|
||||
mLayoutAddUserView.addView(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
package com.tencent.qcloud.tuikit.tuicallkit.view.root;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.tencent.qcloud.tuicore.TUILogin;
|
||||
import com.tencent.qcloud.tuikit.TUICommonDefine;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.R;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.CallingUserModel;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.TUICallingStatusManager;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.UserLayout;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.base.UserLayoutEntity;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.utils.DisplayUtils;
|
||||
import com.tencent.qcloud.tuikit.tuicallkit.view.UserLayoutFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class TUICallingSingleView extends BaseCallView {
|
||||
private Context mContext;
|
||||
private UserLayoutFactory mUserLayoutFactory;
|
||||
private TextView mTextTime;
|
||||
private RelativeLayout mLayoutUserWaitView;
|
||||
private RelativeLayout mLayoutSwitchAudio;
|
||||
private RelativeLayout mLayoutFunction;
|
||||
private RelativeLayout mLayoutFloatView;
|
||||
private RelativeLayout mLayoutUserContainer;
|
||||
|
||||
private ArrayList<LayoutParams> mFloatParamList;
|
||||
private int mCount = 0;
|
||||
|
||||
public TUICallingSingleView(Context context, UserLayoutFactory factory) {
|
||||
super(context);
|
||||
mContext = context.getApplicationContext();
|
||||
mUserLayoutFactory = factory;
|
||||
initView();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
initData();
|
||||
}
|
||||
|
||||
public void initView() {
|
||||
LayoutInflater.from(mContext).inflate(R.layout.tuicalling_background_single_view, this);
|
||||
mLayoutUserContainer = findViewById(R.id.rl_video_container);
|
||||
mLayoutFloatView = findViewById(R.id.rl_float_view);
|
||||
mLayoutUserWaitView = findViewById(R.id.rl_single_video_user);
|
||||
mLayoutSwitchAudio = findViewById(R.id.rl_switch_audio);
|
||||
mTextTime = findViewById(R.id.tv_single_time);
|
||||
mLayoutFunction = findViewById(R.id.rl_single_function);
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
for (UserLayoutEntity entity : mUserLayoutFactory.mLayoutEntityList) {
|
||||
if (null != entity && !TextUtils.isEmpty(entity.userId) && entity.userId.equals(TUILogin.getLoginUser())) {
|
||||
UserLayout layout = allocUserLayout(entity.userModel);
|
||||
if (layout == null) {
|
||||
continue;
|
||||
}
|
||||
layout.setVideoAvailable(true);
|
||||
if (!TUICallingStatusManager.sharedInstance(mContext).isCameraOpen()) {
|
||||
TUICommonDefine.Camera camera = TUICallingStatusManager.sharedInstance(mContext).getFrontCamera();
|
||||
mCallingAction.openCamera(camera, layout.getVideoView(), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userEnter(CallingUserModel userModel) {
|
||||
super.userEnter(userModel);
|
||||
UserLayout layout = findUserLayout(userModel.userId);
|
||||
if (null == layout) {
|
||||
layout = allocUserLayout(userModel);
|
||||
}
|
||||
|
||||
layout.setVideoAvailable(userModel.isVideoAvailable);
|
||||
mCallingAction.startRemoteView(userModel.userId, layout.getVideoView(),
|
||||
new TUICommonDefine.PlayCallback() {
|
||||
@Override
|
||||
public void onPlaying(String userId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoading(String userId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String userId, int errCode, String errMsg) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void updateUserInfo(CallingUserModel userModel) {
|
||||
super.updateUserInfo(userModel);
|
||||
UserLayout layout = findUserLayout(userModel.userId);
|
||||
if (layout != null) {
|
||||
layout.setVideoAvailable(userModel.isVideoAvailable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateUserView(View view) {
|
||||
super.updateUserView(view);
|
||||
mLayoutUserWaitView.removeAllViews();
|
||||
if (null != view) {
|
||||
mLayoutUserWaitView.addView(view);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSwitchAudioView(View view) {
|
||||
mLayoutSwitchAudio.removeAllViews();
|
||||
if (null != view) {
|
||||
mLayoutSwitchAudio.addView(view);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCallTimeView(String time) {
|
||||
mTextTime.setText(time);
|
||||
mTextTime.setVisibility(TextUtils.isEmpty(time) ? GONE : VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTextColor(int color) {
|
||||
super.updateTextColor(color);
|
||||
mTextTime.setTextColor(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFunctionView(View view) {
|
||||
mLayoutFunction.removeAllViews();
|
||||
if (null != view) {
|
||||
mLayoutFunction.addView(view);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableFloatView(View view) {
|
||||
mLayoutFloatView.removeAllViews();
|
||||
if (null != view) {
|
||||
mLayoutFloatView.addView(view);
|
||||
}
|
||||
}
|
||||
|
||||
public void finish() {
|
||||
recyclerAllUserLayout();
|
||||
super.finish();
|
||||
}
|
||||
|
||||
private UserLayout findUserLayout(String userId) {
|
||||
if (TextUtils.isEmpty(userId)) {
|
||||
return null;
|
||||
}
|
||||
return (null == mUserLayoutFactory) ? null : mUserLayoutFactory.findUserLayout(userId);
|
||||
}
|
||||
|
||||
private UserLayout allocUserLayout(CallingUserModel userModel) {
|
||||
if (null == userModel || TextUtils.isEmpty(userModel.userId)) {
|
||||
return null;
|
||||
}
|
||||
UserLayout userLayout = mUserLayoutFactory.allocUserLayout(userModel);
|
||||
if (null != userLayout.getParent()) {
|
||||
((ViewGroup) userLayout.getParent()).removeView(userLayout);
|
||||
}
|
||||
initGestureListener(userLayout);
|
||||
userLayout.setVisibility(VISIBLE);
|
||||
userLayout.disableAudioImage(true);
|
||||
mLayoutUserContainer.addView(userLayout);
|
||||
mCount++;
|
||||
this.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
makeFloatLayout();
|
||||
}
|
||||
});
|
||||
return userLayout;
|
||||
}
|
||||
|
||||
private void recyclerAllUserLayout() {
|
||||
if (null == mUserLayoutFactory || null == mLayoutUserContainer) {
|
||||
return;
|
||||
}
|
||||
Iterator iterator = mUserLayoutFactory.mLayoutEntityList.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
UserLayoutEntity item = (UserLayoutEntity) iterator.next();
|
||||
mLayoutUserContainer.removeView(item.layout);
|
||||
iterator.remove();
|
||||
}
|
||||
mCount = 0;
|
||||
}
|
||||
|
||||
private void initGestureListener(UserLayout layout) {
|
||||
GestureDetector detector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
|
||||
@Override
|
||||
public boolean onSingleTapUp(MotionEvent e) {
|
||||
layout.performClick();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDown(MotionEvent e) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
||||
if (!layout.isMoveAble()) {
|
||||
return false;
|
||||
}
|
||||
ViewGroup.LayoutParams params = layout.getLayoutParams();
|
||||
if (params instanceof LayoutParams) {
|
||||
LayoutParams layoutParams = (LayoutParams) layout.getLayoutParams();
|
||||
int newX = (int) (layoutParams.leftMargin + (e2.getX() - e1.getX()));
|
||||
int newY = (int) (layoutParams.topMargin + (e2.getY() - e1.getY()));
|
||||
if (newX >= 0 && newX <= (getWidth() - layout.getWidth())
|
||||
&& newY >= 0 && newY <= (getHeight() - layout.getHeight())) {
|
||||
layoutParams.leftMargin = newX;
|
||||
layoutParams.topMargin = newY;
|
||||
layout.setLayoutParams(layoutParams);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
layout.setOnTouchListener(new OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
return detector.onTouchEvent(event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private UserLayoutEntity findEntity(String userId) {
|
||||
for (UserLayoutEntity entity : mUserLayoutFactory.mLayoutEntityList) {
|
||||
if (entity.userId.equals(userId)) {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void makeFloatLayout() {
|
||||
if (null == mFloatParamList || mFloatParamList.size() == 0) {
|
||||
mFloatParamList = DisplayUtils.initFloatParamList(getContext(), getWidth(), getHeight());
|
||||
}
|
||||
|
||||
int size = mUserLayoutFactory.mLayoutEntityList.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
UserLayoutEntity entity = mUserLayoutFactory.mLayoutEntityList.get(size - i - 1);
|
||||
LayoutParams layoutParams = mFloatParamList.get(i);
|
||||
|
||||
entity.layout.setLayoutParams(layoutParams);
|
||||
entity.layout.setMoveAble(i != 0);
|
||||
addFloatViewClickListener(entity);
|
||||
entity.layout.bringToFront();
|
||||
}
|
||||
}
|
||||
|
||||
private void addFloatViewClickListener(UserLayoutEntity entity) {
|
||||
final String userId = entity.userId;
|
||||
entity.layout.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (!TextUtils.isEmpty(userId)) {
|
||||
makeFullVideoView(userId);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void makeFullVideoView(String userId) {
|
||||
UserLayoutEntity entity = findEntity(userId);
|
||||
mUserLayoutFactory.mLayoutEntityList.remove(entity);
|
||||
mUserLayoutFactory.mLayoutEntityList.addLast(entity);
|
||||
makeFloatLayout();
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 696 B |
|
After Width: | Height: | Size: 749 B |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 698 B |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 642 B |
|
After Width: | Height: | Size: 654 B |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 63 KiB |
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/tuicalling_ic_camera_disable" android:state_activated="false" android:state_enabled="true" />
|
||||
<item android:drawable="@drawable/tuicalling_ic_camera_enable" android:state_activated="true" android:state_enabled="true" />
|
||||
</selector>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/tuicalling_ic_dialing_pressed" android:state_pressed="true" android:state_enabled="true" />
|
||||
<item android:drawable="@drawable/tuicalling_ic_dialing" android:state_pressed="false" android:state_enabled="true" />
|
||||
</selector>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/tuicalling_color_white" />
|
||||
<corners android:radius="15dp" />
|
||||
</shape>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/tuicalling_color_bg_float_view" />
|
||||
<corners
|
||||
android:bottomRightRadius="15dp"
|
||||
android:topRightRadius="15dp" />
|
||||
</shape>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/tuicalling_color_bg_float_view" />
|
||||
<corners
|
||||
android:bottomLeftRadius="15dp"
|
||||
android:topLeftRadius="15dp" />
|
||||
</shape>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/tuicalling_ic_handsfree_enable" android:state_activated="true" android:state_enabled="true" />
|
||||
<item android:drawable="@drawable/tuicalling_ic_handsfree_disable" android:state_activated="false" android:state_enabled="true" />
|
||||
</selector>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/tuicalling_ic_hangup_pressed" android:state_enabled="true" android:state_pressed="true" />
|
||||
<item android:drawable="@drawable/tuicalling_ic_hangup" android:state_enabled="true" android:state_pressed="false" />
|
||||
</selector>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/tuicalling_ic_mic_unmute" android:state_activated="true" android:state_enabled="true" />
|
||||
<item android:drawable="@drawable/tuicalling_ic_mic_mute" android:state_activated="false" android:state_enabled="true" />
|
||||
</selector>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:gravity="center">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:scaleType="centerCrop" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6.5dp"
|
||||
android:includeFontPadding="false"
|
||||
android:textColor="@color/tuicalling_color_gray"
|
||||
android:textSize="10sp" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/gl_horizontal_top"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintGuide_begin="20dp" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/group_layout_manager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/rl_add_user_view" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/rl_float_view"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="@color/tuicalling_color_transparent"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/rl_add_user_view"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/rl_add_user_view" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/rl_add_user_view"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:background="@color/tuicalling_color_transparent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/gl_horizontal_top" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_group_call_hint"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@id/tv_group_time"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/group_layout_manager" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_group_time"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textSize="12sp"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintBottom_toTopOf="@+id/rl_group_function"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/rl_group_function"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/cl_root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/gl_horizontal_top"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintGuide_begin="20dp" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/rl_single_audio_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="98dp"
|
||||
android:gravity="center_horizontal"
|
||||
app:layout_constraintBottom_toTopOf="@id/tv_call_hint"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/gl_horizontal_top" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/rl_float_view"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:background="@color/tuicalling_color_transparent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/gl_horizontal_top" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/rl_add_user_view"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:background="@color/tuicalling_color_transparent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/gl_horizontal_top" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_call_hint"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="12dp"
|
||||
android:textColor="@color/tuicalling_color_black"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/rl_single_audio_view" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_other_user_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_call_hint" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_image_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="12dp"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/rl_image_function"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/rl_image_function"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/cl_root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/tuicalling_color_video_background">
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/gl_horizontal_top"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintGuide_begin="20dp" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/rl_video_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/rl_float_view"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="20dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/rl_single_video_user"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/rl_single_video_user" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/rl_single_video_user"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="64dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/gl_horizontal_top" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_single_call_hint"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/tuicalling_color_black"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toTopOf="@id/tv_single_time"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_single_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="12dp"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/rl_switch_audio"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/rl_switch_audio"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toTopOf="@id/rl_single_function"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/rl_single_function"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/rl_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:background="@drawable/tuicalling_bg_floatwindow"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/rl_video_view"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="120dp"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.tencent.qcloud.tuicore.component.RoundCornerImageView
|
||||
android:id="@+id/img_float_avatar"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:visibility="gone"
|
||||
app:corner_radius="15dp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/float_audioView"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_margin="4dp"
|
||||
android:src="@drawable/tuicalling_ic_float" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_float_hint"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:text="@string/tuicalling_wait_resonse"
|
||||
android:textColor="@color/tuicalling_color_green"
|
||||
android:textSize="12sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_float_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:textColor="@color/tuicalling_color_green"
|
||||
android:textSize="12sp"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="20dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_mute"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/ll_hangup"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/img_mute"
|
||||
android:layout_width="52dp"
|
||||
android:layout_height="52dp"
|
||||
android:src="@drawable/tuicalling_bg_mute_mic" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/tuicalling_text_microphone"
|
||||
android:textColor="@color/tuicalling_color_second"
|
||||
android:textSize="@dimen/tuicalling_text_size_hint" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_hangup"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/ll_handsfree"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/ll_mute"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/img_hangup"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:src="@drawable/tuicalling_bg_hangup" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/tuicalling_text_hangup"
|
||||
android:textColor="@color/tuicalling_color_second"
|
||||
android:textSize="@dimen/tuicalling_text_size_hint" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_handsfree"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/ll_hangup"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/img_handsfree"
|
||||
android:layout_width="52dp"
|
||||
android:layout_height="52dp"
|
||||
android:src="@drawable/tuicalling_bg_handsfree" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/tuicalling_text_speaker"
|
||||
android:textColor="@color/tuicalling_color_second"
|
||||
android:textSize="@dimen/tuicalling_text_size_hint" />
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="36dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_decline"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/ll_answer"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:src="@drawable/tuicalling_bg_hangup" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_reject"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/tuicalling_text_reject"
|
||||
android:textColor="@color/tuicalling_color_second"
|
||||
android:textSize="@dimen/tuicalling_text_size_hint" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_answer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/ll_decline"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:src="@drawable/tuicalling_bg_dialing" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_dialing"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/tuicalling_text_dialing"
|
||||
android:textColor="@color/tuicalling_color_second"
|
||||
android:textSize="@dimen/tuicalling_text_size_hint" />
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -0,0 +1,132 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="20dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_mute"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintEnd_toStartOf="@+id/ll_handsfree"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_mute"
|
||||
android:layout_width="52dp"
|
||||
android:layout_height="52dp"
|
||||
android:src="@drawable/tuicalling_bg_mute_mic" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_mic"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/tuicalling_text_microphone"
|
||||
android:textColor="@color/tuicalling_color_white"
|
||||
android:textSize="@dimen/tuicalling_text_size_hint" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_handsfree"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintEnd_toStartOf="@+id/ll_open_camera"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/ll_mute"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_handsfree"
|
||||
android:layout_width="52dp"
|
||||
android:layout_height="52dp"
|
||||
android:src="@drawable/tuicalling_bg_handsfree" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_speaker"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/tuicalling_text_speaker"
|
||||
android:textColor="@color/tuicalling_color_white"
|
||||
android:textSize="@dimen/tuicalling_text_size_hint" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_open_camera"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toEndOf="@+id/ll_handsfree"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/img_camera"
|
||||
android:layout_width="52dp"
|
||||
android:layout_height="52dp"
|
||||
android:src="@drawable/tuicalling_bg_camera" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/tuicalling_text_camera"
|
||||
android:textColor="@color/tuicalling_color_white"
|
||||
android:textSize="@dimen/tuicalling_text_size_hint" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_hangup"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/ll_mute">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:src="@drawable/tuicalling_bg_hangup" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/tuicalling_text_hangup"
|
||||
android:textColor="@color/tuicalling_color_white"
|
||||
android:textSize="@dimen/tuicalling_text_size_hint" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/switch_camera"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginBottom="28dp"
|
||||
android:src="@drawable/tuicalling_ic_switch_camera"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/ll_hangup"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/ll_hangup"
|
||||
app:layout_constraintTop_toTopOf="@+id/ll_hangup" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="20dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_cancel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:src="@drawable/tuicalling_bg_hangup" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/tuicalling_btn_cancel"
|
||||
android:textColor="@color/tuicalling_color_white"
|
||||
android:textSize="@dimen/tuicalling_text_size_hint" />
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/img_switch_camera"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginBottom="28dp"
|
||||
android:src="@drawable/tuicalling_ic_switch_camera"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/ll_cancel"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/ll_cancel"
|
||||
app:layout_constraintTop_toTopOf="@+id/ll_cancel" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:parentTag="android.widget.RelativeLayout">
|
||||
|
||||
<com.tencent.qcloud.tuikit.TUIVideoView
|
||||
android:id="@+id/tx_cloud_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.tencent.qcloud.tuicore.component.RoundCornerImageView
|
||||
android:id="@+id/img_head"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:scaleType="fitXY"
|
||||
android:src="@drawable/tuicalling_ic_avatar" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/img_loading"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:layout_centerInParent="true"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:background="@color/tuicalling_color_transparent"
|
||||
android:textColor="@color/tuicalling_color_white"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_audio_input"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:background="@drawable/tuicalling_ic_mic_mute"
|
||||
android:visibility="gone" />
|
||||
</merge>
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/cl_root"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.tencent.qcloud.tuicore.component.RoundCornerImageView
|
||||
android:id="@+id/iv_user_avatar"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="80dp"
|
||||
android:src="@drawable/tuicalling_ic_avatar"
|
||||
app:corner_radius="15dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_user_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:paddingLeft="20dp"
|
||||
android:text="@string/tuicalling_contact_default_name"
|
||||
android:textColor="@color/tuicalling_color_white"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintEnd_toStartOf="@+id/iv_user_avatar"
|
||||
app:layout_constraintHorizontal_bias="1.0"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintTop_toTopOf="@+id/iv_user_avatar" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_video_tag"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:textColor="@color/tuicalling_color_white"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/iv_user_avatar"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_user_name" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="20dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_switch_audio"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="19dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:src="@drawable/tuicalling_ic_switch_to_audio_call" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/tuicalling_switch_audio_call"
|
||||
android:textColor="@color/tuicalling_color_white"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.tencent.qcloud.tuicore.component.RoundCornerImageView
|
||||
android:id="@+id/img_avatar"
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="120dp"
|
||||
android:src="@drawable/tuicalling_ic_avatar"
|
||||
app:corner_radius="15dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tv_name"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="@string/tuicalling_contact_default_name"
|
||||
android:textColor="@color/tuicalling_color_black"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/img_avatar" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -0,0 +1,50 @@
|
||||
<resources>
|
||||
<string name="tuicalling_contact_default_name">test 123</string>
|
||||
<string name="tuicalling_toast_call_error_msg">Error [%1$d]:%2$s.</string>
|
||||
<string name="tuicalling_toast_user_reject_call">%1$s declined the call.</string>
|
||||
<string name="tuicalling_toast_user_not_response">%1$s didn’t answer.</string>
|
||||
<string name="tuicalling_toast_user_busy">%1$s is busy.</string>
|
||||
<string name="tuicalling_toast_user_cancel_call">%1$s cancelled the call.</string>
|
||||
<string name="tuicalling_toast_user_timeout">%1$s timed out.</string>
|
||||
<string name="tuicalling_toast_enable_mute">Muted</string>
|
||||
<string name="tuicalling_toast_disable_mute">Unmuted</string>
|
||||
<string name="tuicalling_toast_speaker">Speaker</string>
|
||||
<string name="tuicalling_toast_use_handset">Earpiece</string>
|
||||
<string name="tuicalling_called_time_format">%02d:%02d</string>
|
||||
<string name="tuicalling_toast_user_end">%s end the call.</string>
|
||||
<string name="tuicalling_other_party_network_low_quality">The other party\'s network connection is poor</string>
|
||||
<string name="tuicalling_self_network_low_quality">Your network connection is poor</string>
|
||||
<string name="tuicalling_toast_switch_camera">Switch Camera</string>
|
||||
<string name="tuicalling_toast_enable_camera">Camera On</string>
|
||||
<string name="tuicalling_toast_disable_camera">Camera Off</string>
|
||||
<string name="tuicalling_waiting_accept">Waiting for the user to accept…</string>
|
||||
<string name="tuicalling_invite_audio_call">Invited you to a voice call…</string>
|
||||
<string name="tuicalling_invite_video_call">Invites you to a video call…</string>
|
||||
<string name="tuicalling_text_microphone">Mic</string>
|
||||
<string name="tuicalling_text_hangup">Hang Up</string>
|
||||
<string name="tuicalling_text_reject">Decline</string>
|
||||
<string name="tuicalling_text_speaker">Speaker</string>
|
||||
<string name="tuicalling_text_dialing">Answer</string>
|
||||
<string name="tuicalling_text_camera">Camera</string>
|
||||
<string name="tuicalling_switch_camera_hint">Turn on your camera first</string>
|
||||
<string name="tuicalling_switch_audio_call">Switch to Voice Call</string>
|
||||
<string name="tuicalling_btn_cancel">Cancel</string>
|
||||
<string name="tuicalling_tips_start_audio">Please turn on the microphone permissions first</string>
|
||||
<string name="tuicalling_video_call">Video Call</string>
|
||||
<string name="tuicalling_audio_call">Voice Call</string>
|
||||
<string name="tuicalling_user_kicked_offline">You have been kicked off the line. Please log in again!</string>
|
||||
<string name="tuicalling_user_sig_expired">Your user signature information has expired</string>
|
||||
<string name="tuicalling_user_exceed_limit">TUICalling currently supports call with up to 9 people.For larger conference calls,try using TUIRoom</string>
|
||||
<string name="tuicalling_wait_resonse">Waiting</string>
|
||||
<string name="tuicalling_is_calling">Unable to restart the call</string>
|
||||
<string name="tuicalling_tips_start_camera">Please turn on the camera permission first</string>
|
||||
<string name="tuicalling_permission_mic_reason_title">%s applies for access to the microphone</string>
|
||||
<string name="tuicalling_permission_mic_reason">Needs access to your microphone, and it can be used for functions such as Audio/Video Call, Group Audio/Video Call etc.</string>
|
||||
<string name="tuicalling_permission_camera_reason_title">%s applies for camera permission</string>
|
||||
<string name="tuicalling_permission_camera_reason">Needs access to your camera, and it can be used for functions such as Video Call, Group Video Call etc. For beauty filters to work, we will collect the facial information captured by your camera in real time to detect your facial features.</string>
|
||||
<string name="tuicalling_package_not_purchased">You do not have TUICallKit package, please open the free experience in the console or purchase the official package</string>
|
||||
<string name="tuicalling_package_not_support">The package you purchased does not support this ability</string>
|
||||
<string name="tuicalling_status_is_not_accept">You can only use this function after you accept the call</string>
|
||||
<string name="tuicalling_groupid_is_empty">groupId is empty</string>
|
||||
<string name="tuicalling_have_a_new_call">You have a new call</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,50 @@
|
||||
<resources>
|
||||
<string name="tuicalling_contact_default_name">测试123</string>
|
||||
<string name="tuicalling_toast_call_error_msg">发生错误[%1$d]:%2$s</string>
|
||||
<string name="tuicalling_toast_user_reject_call">%1$s拒绝通话</string>
|
||||
<string name="tuicalling_toast_user_not_response">%1$s无响应</string>
|
||||
<string name="tuicalling_toast_user_busy">%1$s忙线</string>
|
||||
<string name="tuicalling_toast_user_cancel_call">%1$s取消了通话</string>
|
||||
<string name="tuicalling_toast_user_timeout">%1$s通话超时</string>
|
||||
<string name="tuicalling_toast_enable_mute">开启静音</string>
|
||||
<string name="tuicalling_toast_disable_mute">关闭静音</string>
|
||||
<string name="tuicalling_toast_speaker">使用扬声器</string>
|
||||
<string name="tuicalling_toast_use_handset">使用听筒</string>
|
||||
<string name="tuicalling_called_time_format">%02d:%02d</string>
|
||||
<string name="tuicalling_toast_user_end">%s 结束通话</string>
|
||||
<string name="tuicalling_other_party_network_low_quality">对方网络不佳</string>
|
||||
<string name="tuicalling_self_network_low_quality">己方网络不佳</string>
|
||||
<string name="tuicalling_toast_switch_camera">切换摄像头</string>
|
||||
<string name="tuicalling_toast_enable_camera">开启摄像头</string>
|
||||
<string name="tuicalling_toast_disable_camera">关闭摄像头</string>
|
||||
<string name="tuicalling_waiting_accept">正在等待对方接受邀请...</string>
|
||||
<string name="tuicalling_invite_audio_call">邀请您进行语音通话…</string>
|
||||
<string name="tuicalling_invite_video_call">邀请您进行视频通话…</string>
|
||||
<string name="tuicalling_text_microphone">麦克风</string>
|
||||
<string name="tuicalling_text_hangup">挂断</string>
|
||||
<string name="tuicalling_text_reject">拒接</string>
|
||||
<string name="tuicalling_text_speaker">扬声器</string>
|
||||
<string name="tuicalling_text_dialing">接听</string>
|
||||
<string name="tuicalling_text_camera">摄像头</string>
|
||||
<string name="tuicalling_switch_camera_hint">请先打开摄像头</string>
|
||||
<string name="tuicalling_switch_audio_call">切到语音通话</string>
|
||||
<string name="tuicalling_btn_cancel">取消</string>
|
||||
<string name="tuicalling_tips_start_audio">请先打开麦克风权限</string>
|
||||
<string name="tuicalling_video_call">视频通话</string>
|
||||
<string name="tuicalling_audio_call">语音通话</string>
|
||||
<string name="tuicalling_user_kicked_offline">您已被踢下线,请重新登录</string>
|
||||
<string name="tuicalling_user_sig_expired">您的用户签名信息已过期</string>
|
||||
<string name="tuicalling_user_exceed_limit">暂支持最多9人通话。如需多人会议,请使用TUIRoom</string>
|
||||
<string name="tuicalling_wait_resonse">等待接听</string>
|
||||
<string name="tuicalling_is_calling">正在通话中,无法再次发起</string>
|
||||
<string name="tuicalling_tips_start_camera">请先打开相机权限</string>
|
||||
<string name="tuicalling_permission_camera_reason_title">%s申请获取相机权限</string>
|
||||
<string name="tuicalling_permission_camera_reason">需要访问您的相机权限,开启后用于视频通话、多人视频通话等功能,在您使用美颜功能时,我们会对您实时拍摄的面部的像素信息进行实时智能识别,在识别过程中会实时收集您面部的像素信息,以为您提供更好的美颜效果。</string>
|
||||
<string name="tuicalling_permission_mic_reason_title">%s申请获取麦克风权限</string>
|
||||
<string name="tuicalling_permission_mic_reason">需要访问您的麦克风权限,开启后用于语音通话、多人语音通话、视频通话、多人视频通话等功能,并且开启后录制的视频才会有声音</string>
|
||||
<string name="tuicalling_package_not_purchased">您当前未购买音视频通话能力套餐,请前往 IM 控制台开通免费体验或加购正式版</string>
|
||||
<string name="tuicalling_package_not_support">您当前购买的音视频通话能力套餐不支持该功能,建议您升级套餐类型</string>
|
||||
<string name="tuicalling_status_is_not_accept">接听后才能使用该功能</string>
|
||||
<string name="tuicalling_groupid_is_empty">群ID为空</string>
|
||||
<string name="tuicalling_have_a_new_call">您有一个新的通话</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="tuicalling_color_white">#FFFFFFFF</color>
|
||||
<color name="tuicalling_color_black">#000000</color>
|
||||
<color name="tuicalling_color_second">#666666</color>
|
||||
<color name="tuicalling_color_audio_background">#FFF1F2F8</color>
|
||||
<color name="tuicalling_color_video_background">#FF55534F</color>
|
||||
<color name="tuicalling_color_transparent">#00000000</color>
|
||||
<color name="tuicalling_color_green">#FF29CC85</color>
|
||||
<color name="tuicalling_color_bg_float_view">#FFBBBBBB</color>
|
||||
<color name="tuicalling_color_gray">#696969</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="tuicalling_small_image_size">30dp</dimen>
|
||||
<dimen name="tuicalling_small_image_left_margin">5dp</dimen>
|
||||
<dimen name="tuicalling_text_size_hint">12sp</dimen>
|
||||
</resources>
|
||||
@@ -0,0 +1,50 @@
|
||||
<resources>
|
||||
<string name="tuicalling_contact_default_name">test 123</string>
|
||||
<string name="tuicalling_toast_call_error_msg">Error [%1$d]:%2$s.</string>
|
||||
<string name="tuicalling_toast_user_reject_call">%1$s declined the call.</string>
|
||||
<string name="tuicalling_toast_user_not_response">%1$s didn’t answer.</string>
|
||||
<string name="tuicalling_toast_user_busy">%1$s is busy.</string>
|
||||
<string name="tuicalling_toast_user_cancel_call">%1$s cancelled the call.</string>
|
||||
<string name="tuicalling_toast_user_timeout">%1$s timed out.</string>
|
||||
<string name="tuicalling_toast_enable_mute">Muted</string>
|
||||
<string name="tuicalling_toast_disable_mute">Unmuted</string>
|
||||
<string name="tuicalling_toast_speaker">Speaker</string>
|
||||
<string name="tuicalling_toast_use_handset">Earpiece</string>
|
||||
<string name="tuicalling_called_time_format">%02d:%02d</string>
|
||||
<string name="tuicalling_toast_user_end">%s end the call.</string>
|
||||
<string name="tuicalling_other_party_network_low_quality">The other party\'s network connection is poor</string>
|
||||
<string name="tuicalling_self_network_low_quality">Your network connection is poor</string>
|
||||
<string name="tuicalling_toast_switch_camera">Switch Camera</string>
|
||||
<string name="tuicalling_toast_enable_camera">Camera On</string>
|
||||
<string name="tuicalling_toast_disable_camera">Camera Off</string>
|
||||
<string name="tuicalling_waiting_accept">Waiting for the user to accept…</string>
|
||||
<string name="tuicalling_invite_audio_call">Invited you to a voice call…</string>
|
||||
<string name="tuicalling_invite_video_call">Invites you to a video call…</string>
|
||||
<string name="tuicalling_text_microphone">Mic</string>
|
||||
<string name="tuicalling_text_hangup">Hang Up</string>
|
||||
<string name="tuicalling_text_reject">Decline</string>
|
||||
<string name="tuicalling_text_speaker">Speaker</string>
|
||||
<string name="tuicalling_text_dialing">Answer</string>
|
||||
<string name="tuicalling_text_camera">Camera</string>
|
||||
<string name="tuicalling_switch_camera_hint">Turn on your camera first</string>
|
||||
<string name="tuicalling_switch_audio_call">Switch to Voice Call</string>
|
||||
<string name="tuicalling_btn_cancel">Cancel</string>
|
||||
<string name="tuicalling_tips_start_audio">Please turn on the microphone permissions first</string>
|
||||
<string name="tuicalling_video_call">Video Call</string>
|
||||
<string name="tuicalling_audio_call">Voice Call</string>
|
||||
<string name="tuicalling_user_kicked_offline">You have been kicked off the line. Please log in again!</string>
|
||||
<string name="tuicalling_user_sig_expired">Your user signature information has expired</string>
|
||||
<string name="tuicalling_user_exceed_limit">TUICalling currently supports call with up to 9 people.For larger conference calls,try using TUIRoom</string>
|
||||
<string name="tuicalling_wait_resonse">Waiting</string>
|
||||
<string name="tuicalling_is_calling">Unable to restart the call</string>
|
||||
<string name="tuicalling_tips_start_camera">Please turn on the camera permission first</string>
|
||||
<string name="tuicalling_permission_mic_reason_title">%s applies for access to the microphone</string>
|
||||
<string name="tuicalling_permission_mic_reason">Needs access to your microphone, and it can be used for functions such as Audio/Video Call, Group Audio/Video Call etc.</string>
|
||||
<string name="tuicalling_permission_camera_reason_title">%s applies for camera permission</string>
|
||||
<string name="tuicalling_permission_camera_reason">Needs access to your camera, and it can be used for functions such as Video Call, Group Video Call etc. For beauty filters to work, we will collect the facial information captured by your camera in real time to detect your facial features.</string>
|
||||
<string name="tuicalling_package_not_purchased">You do not have TUICallKit package, please open the free experience in the console or purchase the official package</string>
|
||||
<string name="tuicalling_package_not_support">The package you purchased does not support this ability</string>
|
||||
<string name="tuicalling_status_is_not_accept">You can only use this function after you accept the call</string>
|
||||
<string name="tuicalling_groupid_is_empty">groupId is empty</string>
|
||||
<string name="tuicalling_have_a_new_call">You have a new call</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
</resources>
|
||||