Commit 1cc72a1f by 霍志良

Merge remote-tracking branch 'origin/dev_mdt_av' into new_dev_4.3.89

# Conflicts:
#	config.gradle
parents 2c0c76b2 22643ca0
......@@ -12,7 +12,8 @@ kapt {
}
android {
compileSdkVersion 28
compileSdkVersion rootProject.ext.android["compileSdkVersion"]
buildToolsVersion rootProject.ext.android["buildToolsVersion"]
compileOptions {
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_1_8
......@@ -20,8 +21,8 @@ android {
defaultConfig {
applicationId "com.ydl.component"
minSdkVersion 21
targetSdkVersion 28
minSdkVersion rootProject.ext.android["minSdkVersion"]
targetSdkVersion rootProject.ext.android["targetSdkVersion"]
versionCode 1
versionName "1.0"
multiDexEnabled true
......@@ -37,7 +38,7 @@ android {
multiDexEnabled true
ndk {
abiFilters "arm64-v8a" // 指定要ndk需要兼容的架构(这样其他依赖包里mips,x86,armeabi,arm-v8之类的so会被过滤掉)
abiFilters "arm64-v8a","armeabi-v7a" // 指定要ndk需要兼容的架构(这样其他依赖包里mips,x86,armeabi,arm-v8之类的so会被过滤掉)
}
}
......@@ -175,14 +176,21 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation(rootProject.ext.dependencies["appcompat-v7"])
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
// kapt rootProject.ext.dependencies["dagger2-compiler"]
api rootProject.ext.dependencies["butterknife"]
kapt rootProject.ext.dependencies["butterknife-compiler"]
implementation(rootProject.ext.dependencies["design"])
implementation(rootProject.ext.dependencies["appcompat-v7"])
implementation(rootProject.ext.dependencies["espresso-core"])
implementation(rootProject.ext.dependencies["okhttp3"])
// TPNS SDK 主工程依赖包
// implementation 'com.tencent.liteav:LiteAVSDK_TRTC:latest.release'
if (true) {
//开发模式
......@@ -221,8 +229,9 @@ dependencies {
implementation project(':m-fm')
implementation modularPublication('com.ydl:m-fm-api')
} else {
implementation project(':ydl-tuicore')
} else {
//发布模式
api 'com.ydl:m-user-module-ydl:0.0.6'
api rootProject.ext.dependencies["ydl-webview"]
......@@ -232,6 +241,9 @@ dependencies {
api(rootProject.ext.dependencies["ydl-platform"]) {
transitive = true
}
api(rootProject.ext.dependencies["ydl-tuicalling"]) {
transitive = true
}
}
......
......@@ -74,7 +74,46 @@
<activity
android:name=".home.HomeActivity"
android:launchMode="singleTask"
android:noHistory="true"></activity>
android:noHistory="true"/>
<activity
android:name=".rtc.MDTLoginActivity"
android:launchMode="singleTask"
android:theme="@style/Theme.AppCompat.NoActionBar" />
<activity
android:name=".rtc.MDTMainActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="com.tencent.liteav.action.portal" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="com.tencent.qcloud"
android:path="/detail"
android:scheme="pushscheme" />
</intent-filter>
<intent-filter>
<action android:name="com.tencent.trtc.tuicalling" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".rtc.ProfileActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.NoActionBar" />
<activity
android:name=".rtc.TUICallingEntranceActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.NoActionBar" />
<activity android:name=".rtc.VideoCallingEnterActivity" />
</application>
</manifest>
\ No newline at end of file
......@@ -20,6 +20,7 @@ import com.ydl.component.music.FragmentContainerActivity
import com.ydl.component.mvp.DemoContract
import com.ydl.component.mvp.DemoPresenter
import com.ydl.component.route.PlatformTempCommonRouteImpl
import com.ydl.component.rtc.MDTLoginActivity
import com.ydl.confide.home.ConfideHomeActivity
import com.ydl.media.audio.PlayService
import com.ydl.ydlcommon.modular.ModularServiceManager
......@@ -83,6 +84,11 @@ class MainActivity : BaseLceActivity<DemoContract.View, DemoContract.Presenter>(
bindService()
reLoadData()
requestPermission()
bt_mdt.setOnClickListener {
val intent = Intent(this, MDTLoginActivity::class.java)
startActivity(intent)
}
tv_user.setOnClickListener {
reLoadData()
}
......
......@@ -9,6 +9,7 @@ import android.webkit.WebView;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.meituan.android.walle.WalleChannelReader;
import com.tencent.qcloud.tuicore.calling.trtccalling.model.TRTCCalling;
import com.umeng.analytics.MobclickAgent;
import com.umeng.commonsdk.UMConfigure;
import com.umeng.socialize.PlatformConfig;
......@@ -21,6 +22,7 @@ import com.ydl.ydlcommon.router.YdlCommonRouterManager;
import com.ydl.ydlcommon.utils.AppProgressUtils;
import com.ydl.ydlcommon.utils.Utils;
import com.yidianling.common.tools.LogUtil;
import com.yidianling.common.tools.ToastUtil;
import com.yidianling.course.lifeCallback.CoursePlayLifecycle;
......@@ -61,6 +63,23 @@ public class ComponentTestApp extends BaseApp {
registerActivityLifecycleCallbacks(new CoursePlayLifecycle());
Fresco.initialize(this);
TRTCCalling.sharedInstance(this).setMdtCallBack(new TRTCCalling.MdtCallBack() {
@Override
public void onReceiveNewInvitation(String roomId) {
ToastUtil.toastShort("电话邀请"+roomId);
}
@Override
public void onInviteeAccepted(String roomId) {
ToastUtil.toastShort("接受邀请"+roomId);
}
@Override
public void onInviteeRejected(String roomId) {
ToastUtil.toastShort("拒绝邀请"+roomId);
}
});
}
private void initUmeng() {
......
......@@ -21,9 +21,9 @@ import java.util.List;
public final class DemoGlobalConfig implements IConfigModule {
String APP_DOMAIN = "https://api.github.com/";
// public static String appEnv = YDLConstants.ENV_AUTO_TEST;
// public static String appEnv = YDLConstants.ENV_TEST;
public static String appEnv = YDLConstants.ENV_TEST;
// public static String appEnv = YDLConstants.ENV_NEW_TEST;//配置未上传到maven库
public static String appEnv = YDLConstants.ENV_PROD;
// public static String appEnv = YDLConstants.ENV_PROD;
@Override
public void injectAppLifecycle(@NotNull Context context, @NotNull List<IAppLifecycles> lifecycles) {
lifecycles.add(new DemoAppLifecycles());
......
package com.ydl.component.rtc
import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import android.view.View
import android.view.WindowManager
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.blankj.utilcode.util.ToastUtils
import com.tencent.imsdk.v2.*
import com.tencent.qcloud.tuicore.TUILogin
import com.tencent.qcloud.tuicore.calling.basic.UserModel
import com.tencent.qcloud.tuicore.calling.basic.UserModelManager
import com.ydl.component.R
import com.ydl.component.rtc.bean.UserSigResponse
import com.ydl.component.rtc.http.MDTHttpImpl.Companion.getInstance
import com.ydl.ydlcommon.modular.ModularServiceManager.provide
import com.yidianling.common.tools.ToastUtil
import com.yidianling.user.api.bean.UserResponseBean
import com.yidianling.user.api.service.IUserService
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import java.util.*
class MDTLoginActivity : AppCompatActivity() {
private var mEditUserId: EditText? = null
private var mButtonLogin: Button? = null
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
initStatusBar()
initView()
}
private fun initView() {
mEditUserId = findViewById<View>(R.id.et_userId) as EditText
initButtonLogin()
}
private fun initButtonLogin() {
mButtonLogin = findViewById<View>(R.id.tv_login) as Button
mButtonLogin!!.setOnClickListener {
getSigin()
}
}
@SuppressLint("CheckResult")
private fun getSigin() {
var user = provide(
IUserService::class.java
).getUserInfo()
val uid = user?.uid
mEditUserId!!.setText(uid)
val userId = mEditUserId!!.text.toString().trim { it <= ' ' }
if (TextUtils.isEmpty(userId)) {
Toast.makeText(this, R.string.user_id_is_empty, Toast.LENGTH_SHORT).show()
return
}
val manager = UserModelManager.getInstance()
val userModel = manager.userModel
uid?.let {uid ->
getInstance().getSecret(UserSigResponse(uid))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ response ->
val data = response.data
if ("200" == response.code) {
userModel.appId = Integer.valueOf(data.appId)
userModel.phone = userId
userModel.userId = userId
userModel.userSig = data.userSig
userModel.userAvatar =user?.head
userModel.userName =user?.nick_name
manager.userModel = userModel
login(userModel)
} else {
ToastUtil.toastShort(response.msg)
}
}, { error ->
ToastUtil.toastShort(error.message)
})
}
}
private fun login(userModel: UserModel) {
val config = V2TIMSDKConfig()
config.logLevel = V2TIMSDKConfig.V2TIM_LOG_DEBUG
TUILogin.init(this, userModel.appId, null, object : V2TIMSDKListener() {
override fun onKickedOffline() {}
override fun onUserSigExpired() {}
})
TUILogin.login(userModel.userId, userModel.userSig, object : V2TIMCallback {
override fun onError(code: Int, msg: String) {
ToastUtils.showLong("登录IM失败,所有功能不可用[%d]%s", code, msg)
Log.d(TAG, "login fail code: $code msg:$msg")
}
override fun onSuccess() {
Log.d(TAG, "login onSuccess")
userInfo
}
})
}//如果用户信息不为空,则直接进入主界面//如果用户名和头像为空,则跳转设置界面进行设置
//先查询用户是否存在
private val userInfo: Unit
private get() {
val manager = UserModelManager.getInstance()
val userModel = manager.userModel
//先查询用户是否存在
val userIdList: MutableList<String> = ArrayList()
userIdList.add(userModel.userId)
Log.d(TAG, "setUserInfo: userIdList = $userIdList")
V2TIMManager.getInstance()
.getUsersInfo(userIdList, object : V2TIMValueCallback<List<V2TIMUserFullInfo>?> {
override fun onError(code: Int, msg: String) {
Log.e(TAG, "get group info list fail, code:$code msg: $msg")
}
override fun onSuccess(resultList: List<V2TIMUserFullInfo>?) {
if (resultList == null || resultList.isEmpty()) {
return
}
val result = resultList[0]
val userName = result.nickName
val userAvatar = result.faceUrl
Log.d(TAG, "onSuccess: userName = $userName , userAvatar = $userAvatar")
//如果用户名和头像为空,则跳转设置界面进行设置
if (TextUtils.isEmpty(userName) || TextUtils.isEmpty(userAvatar)) {
val intent = Intent(this@MDTLoginActivity, ProfileActivity::class.java)
startActivity(intent)
finish()
} else {
userModel.userAvatar = userAvatar
userModel.userName = userName
manager.userModel = userModel
//如果用户信息不为空,则直接进入主界面
val intent = Intent(this@MDTLoginActivity, MDTMainActivity::class.java)
startActivity(intent)
finish()
}
}
})
}
private fun initStatusBar() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val window = window
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
window.statusBarColor = Color.TRANSPARENT
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
}
}
companion object {
private const val TAG = "LoginActivity"
}
}
\ No newline at end of file
package com.ydl.component.rtc;
import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.blankj.utilcode.util.ToastUtils;
import com.tencent.imsdk.v2.V2TIMCallback;
import com.tencent.imsdk.v2.V2TIMManager;
import com.tencent.imsdk.v2.V2TIMUserFullInfo;
import com.tencent.qcloud.tuicore.calling.basic.AvatarConstant;
import com.tencent.qcloud.tuicore.calling.basic.ImageLoader;
import com.tencent.qcloud.tuicore.calling.basic.UserModel;
import com.tencent.qcloud.tuicore.calling.basic.UserModelManager;
import com.ydl.component.R;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ProfileActivity extends AppCompatActivity {
private static final String TAG = "ProfileActivity";
private ImageView mImageAvatar;
private EditText mEditUserName;
private Button mButtonRegister;
private TextView mTvInputTips; //昵称限制提示
private String mAvatarUrl; //用户头像
//自定义随机登录名
private static final int[] CUSTOM_NAME_ARRAY = {
R.string.app_custom_name_1,
R.string.app_custom_name_2,
R.string.app_custom_name_3,
R.string.app_custom_name_4,
R.string.app_custom_name_5,
R.string.app_custom_name_6,
R.string.app_custom_name_7,
R.string.app_custom_name_8,
R.string.app_custom_name_9,
R.string.app_custom_name_10,
R.string.app_custom_name_11,
R.string.app_custom_name_12,
};
private void startMainActivity() {
Intent intent = new Intent();
intent.addCategory("android.intent.category.DEFAULT");
intent.setAction("com.tencent.liteav.action.portal");
startActivity(intent);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login_profile);
initStatusBar();
initView();
}
private void initView() {
mImageAvatar = (ImageView) findViewById(R.id.iv_user_avatar);
mEditUserName = (EditText) findViewById(R.id.et_user_name);
mButtonRegister = (Button) findViewById(R.id.tv_register);
mTvInputTips = (TextView) findViewById(R.id.tv_tips_user_name);
String[] avatarArr = AvatarConstant.USER_AVATAR_ARRAY;
int index = new Random().nextInt(avatarArr.length);
mAvatarUrl = avatarArr[index];
ImageLoader.loadImage(this, mImageAvatar, mAvatarUrl, R.mipmap.ic_avatar);
mButtonRegister.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setProfile();
}
});
int customNameIndex = new Random().nextInt(CUSTOM_NAME_ARRAY.length);
mEditUserName.setText(getString(CUSTOM_NAME_ARRAY[customNameIndex]));
String text = mEditUserName.getText().toString();
if (!TextUtils.isEmpty(text)) {
mEditUserName.setSelection(text.length());
}
mEditUserName.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence text, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence text, int start, int before, int count) {
mButtonRegister.setEnabled(text.length() != 0);
String editable = mEditUserName.getText().toString();
//匹配字母,数字,中文,下划线,以及限制输入长度为2-20.
Pattern p = Pattern.compile("^[a-z0-9A-Z\\u4e00-\\u9fa5\\_]{2,20}$");
Matcher m = p.matcher(editable);
if (!m.matches()) {
mTvInputTips.setTextColor(getResources().getColor(R.color.color_input_no_match));
} else {
mTvInputTips.setTextColor(getResources().getColor(R.color.text_color_hint));
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
}
private void setProfile() {
final String userName = mEditUserName.getText().toString().trim();
if (TextUtils.isEmpty(userName)) {
ToastUtils.showLong(getString(R.string.app_hint_user_name));
return;
}
String reg = "^[a-z0-9A-Z\\u4e00-\\u9fa5\\_]{2,20}$";
if (!userName.matches(reg)) {
mTvInputTips.setTextColor(getResources().getColor(R.color.color_input_no_match));
return;
}
mTvInputTips.setTextColor(getResources().getColor(R.color.text_color_hint));
V2TIMUserFullInfo v2TIMUserFullInfo = new V2TIMUserFullInfo();
v2TIMUserFullInfo.setFaceUrl(mAvatarUrl);
v2TIMUserFullInfo.setNickname(userName);
V2TIMManager.getInstance().setSelfInfo(v2TIMUserFullInfo, new V2TIMCallback() {
@Override
public void onError(int code, String desc) {
Log.e(TAG, "set profile failed errorCode : " + code + " errorMsg : " + desc);
//头像和昵称设置失败,也可以进入到主界面(头像和昵称都用默认值),不影响功能
ToastUtils.showLong(getString(R.string.app_toast_failed_to_set, desc));
startMainActivity();
finish();
}
@Override
public void onSuccess() {
Log.i(TAG, "set profile success.");
ToastUtils.showLong(getString(R.string.app_toast_register_success_and_logging_in));
//成功后保存用户数据
UserModel userModel = UserModelManager.getInstance().getUserModel();
userModel.userName = userName;
userModel.userAvatar = mAvatarUrl;
UserModelManager.getInstance().setUserModel(userModel);
startMainActivity();
finish();
}
});
}
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);
}
}
}
package com.ydl.component.rtc;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.tencent.qcloud.tuicore.calling.videocall.Constant;
import com.tencent.qcloud.tuicore.calling.videocall.VideoCallingActivity;
import com.ydl.component.R;
/**
* TRTC视频通话的入口页面(可以设置房间id和用户id)
*
* - 可跳转TRTC视频通话页面{@link VideoCallingActivity}
*/
/**
* Video Call Entrance View (set room ID and user ID)
*
* - Direct to the video call view: {@link VideoCallingActivity}
*/
public class VideoCallingEnterActivity extends AppCompatActivity {
private EditText mEditInputUserId;
private EditText mEditInputRoomId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.videocall_activit_enter);
mEditInputUserId = findViewById(R.id.et_input_username);
mEditInputRoomId = findViewById(R.id.et_input_room_id);
findViewById(R.id.btn_enter_room).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startEnterRoom();
}
});
findViewById(R.id.rl_entrance_main).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
hideInput();
}
});
findViewById(R.id.iv_back).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
mEditInputRoomId.setText("1256732");
String time = String.valueOf(System.currentTimeMillis());
String userId = time.substring(time.length() - 8);
mEditInputUserId.setText(userId);
}
private void startEnterRoom() {
if (TextUtils.isEmpty(mEditInputUserId.getText().toString().trim())
|| TextUtils.isEmpty(mEditInputRoomId.getText().toString().trim())) {
Toast.makeText(VideoCallingEnterActivity.this, "房间号和用户名不能为空", Toast.LENGTH_LONG).show();
return;
}
Intent intent = new Intent(VideoCallingEnterActivity.this, VideoCallingActivity.class);
intent.putExtra(Constant.ROOM_ID, mEditInputRoomId.getText().toString().trim());
intent.putExtra(Constant.USER_ID, mEditInputUserId.getText().toString().trim());
startActivity(intent);
}
protected void hideInput() {
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
View v = getWindow().peekDecorView();
if (null != v) {
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
}
package com.ydl.component.rtc.bean
/**
* 获取用户密钥
* */
data class UserSigBean(
var appId: String,
var region: String,
var secretId: String,
var userSig: String
)
package com.ydl.component.rtc.bean
/**
* @Author: 刘鹏
* @Description:
* @CreateDate: 2022/4/15 16:37
* -------------------------------
* @UpdateUser:
* @UpdateDate: 2022/4/15 16:37
* @UpdateRemark:
* @Version:
*/
class UserSigResponse(var key: String, var channel: String = "tencent")
\ No newline at end of file
package com.ydl.component.rtc.debug;
import android.text.TextUtils;
import android.util.Base64;
import org.json.JSONException;
import org.json.JSONObject;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.zip.Deflater;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
/*
* Module: GenerateTestUserSig
*
* Function: 用于生成测试用的 UserSig,UserSig 是腾讯云为其云服务设计的一种安全保护签名。
* 其计算方法是对 SDKAppID、UserID 和 EXPIRETIME 进行加密,加密算法为 HMAC-SHA256。
*
* Attention: 请不要将如下代码发布到您的线上正式版本的 App 中,原因如下:
*
* 本文件中的代码虽然能够正确计算出 UserSig,但仅适合快速调通 SDK 的基本功能,不适合线上产品,
* 这是因为客户端代码中的 SECRETKEY 很容易被反编译逆向破解,尤其是 Web 端的代码被破解的难度几乎为零。
* 一旦您的密钥泄露,攻击者就可以计算出正确的 UserSig 来盗用您的腾讯云流量。
*
* 正确的做法是将 UserSig 的计算代码和加密密钥放在您的业务服务器上,然后由 App 按需向您的服务器获取实时算出的 UserSig。
* 由于破解服务器的成本要高于破解客户端 App,所以服务器计算的方案能够更好地保护您的加密密钥。
*
* Reference:https://cloud.tencent.com/document/product/269/32688#Server
*/
public class GenerateTestUserSig {
/**
* 腾讯云 SDKAppId,需要替换为您自己账号下的 SDKAppId。
* <p>
* 进入腾讯云云通信[控制台](https://console.cloud.tencent.com/avc ) 创建应用,即可看到 SDKAppId,
* 它是腾讯云用于区分客户的唯一标识。
*/
public static final int SDKAPPID = 1400646402;
/**
* 签名过期时间,建议不要设置的过短
* <p>
* 时间单位:秒
* 默认时间:7 x 24 x 60 x 60 = 604800 = 7 天
*/
private static final int EXPIRETIME = 604800;
/**
* 向后台请求推拉流地址
* <p>
* key:url_push 获取RTMP推流地址
* key:url_play_flv 获取FLV播放地址
*/
public static final String URL_FETCH_PUSH_URL = "PLACEHOLDER";
/**
* 计算签名用的加密密钥,获取步骤如下:
* <p>
* step1. 进入腾讯云云通信[控制台](https://console.cloud.tencent.com/avc ) ,如果还没有应用就创建一个,
* step2. 单击“应用配置”进入基础配置页面,并进一步找到“帐号体系集成”部分。
* step3. 点击“查看密钥”按钮,就可以看到计算 UserSig 使用的加密的密钥了,请将其拷贝并复制到如下的变量中
* <p>
* 注意:该方案仅适用于调试Demo,正式上线前请将 UserSig 计算代码和密钥迁移到您的后台服务器上,以避免加密密钥泄露导致的流量盗用。
* 文档:https://cloud.tencent.com/document/product/269/32688#Server
*/
private static final String SECRETKEY = "84ed667420eee66e4d99de8d7f76b40ca6b9f8fffacb885068aaa9493cae7a0a";
/**
* 计算 UserSig 签名
* <p>
* 函数内部使用 HMAC-SHA256 非对称加密算法,对 SDKAPPID、userId 和 EXPIRETIME 进行加密。
*
* @note: 请不要将如下代码发布到您的线上正式版本的 App 中,原因如下:
* <p>
* 本文件中的代码虽然能够正确计算出 UserSig,但仅适合快速调通 SDK 的基本功能,不适合线上产品,
* 这是因为客户端代码中的 SECRETKEY 很容易被反编译逆向破解,尤其是 Web 端的代码被破解的难度几乎为零。
* 一旦您的密钥泄露,攻击者就可以计算出正确的 UserSig 来盗用您的腾讯云流量。
* <p>
* 正确的做法是将 UserSig 的计算代码和加密密钥放在您的业务服务器上,然后由 App 按需向您的服务器获取实时算出的 UserSig。
* 由于破解服务器的成本要高于破解客户端 App,所以服务器计算的方案能够更好地保护您的加密密钥。
* <p>
* 文档:https://cloud.tencent.com/document/product/269/32688#Server
*/
public static String genTestUserSig(String userId) {
// return GenTLSSignature(SDKAPPID, userId, EXPIRETIME, null, SECRETKEY);
return "eJyrVgrxCdZLrSjILEpVsjIzMLEwMNABi5WlFilZKRnpGShB*MUp2YkFBZkpSlaGJgYGZiZmJgZGEJnMlNS8ksy0TLAGQ2MDS1NjSzNLmLbMdKCoiVNEmHl6lpt2kEtVoUdaUl5iWGSgV3JuuIVjiYebRZ6XdklEpktquFtJpC1UY0lmLtBFhmYmlpaGppbGprUAOugw0Q__";
}
/**
* 生成 tls 票据
*
* @param sdkappid 应用的 appid
* @param userId 用户 id
* @param expire 有效期,单位是秒
* @param userbuf 默认填写null
* @param priKeyContent 生成 tls 票据使用的私钥内容
* @return 如果出错,会返回为空,或者有异常打印,成功返回有效的票据
*/
private static String GenTLSSignature(long sdkappid, String userId, long expire, byte[] userbuf, String priKeyContent) {
if (TextUtils.isEmpty(priKeyContent)) {
return "";
}
long currTime = System.currentTimeMillis() / 1000;
JSONObject sigDoc = new JSONObject();
try {
sigDoc.put("TLS.ver", "2.0");
sigDoc.put("TLS.identifier", userId);
sigDoc.put("TLS.sdkappid", sdkappid);
sigDoc.put("TLS.expire", expire);
sigDoc.put("TLS.time", currTime);
} catch (JSONException e) {
e.printStackTrace();
}
String base64UserBuf = null;
if (null != userbuf) {
base64UserBuf = Base64.encodeToString(userbuf, Base64.NO_WRAP);
try {
sigDoc.put("TLS.userbuf", base64UserBuf);
} catch (JSONException e) {
e.printStackTrace();
}
}
String sig = hmacsha256(sdkappid, userId, currTime, expire, priKeyContent, base64UserBuf);
if (sig.length() == 0) {
return "";
}
try {
sigDoc.put("TLS.sig", sig);
} catch (JSONException e) {
e.printStackTrace();
}
Deflater compressor = new Deflater();
compressor.setInput(sigDoc.toString().getBytes(Charset.forName("UTF-8")));
compressor.finish();
byte[] compressedBytes = new byte[2048];
int compressedBytesLength = compressor.deflate(compressedBytes);
compressor.end();
return new String(base64EncodeUrl(Arrays.copyOfRange(compressedBytes, 0, compressedBytesLength)));
}
private static String hmacsha256(long sdkappid, String userId, long currTime, long expire, String priKeyContent, String base64Userbuf) {
String contentToBeSigned = "TLS.identifier:" + userId + "\n"
+ "TLS.sdkappid:" + sdkappid + "\n"
+ "TLS.time:" + currTime + "\n"
+ "TLS.expire:" + expire + "\n";
if (null != base64Userbuf) {
contentToBeSigned += "TLS.userbuf:" + base64Userbuf + "\n";
}
try {
byte[] byteKey = priKeyContent.getBytes("UTF-8");
Mac hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec keySpec = new SecretKeySpec(byteKey, "HmacSHA256");
hmac.init(keySpec);
byte[] byteSig = hmac.doFinal(contentToBeSigned.getBytes("UTF-8"));
return new String(Base64.encode(byteSig, Base64.NO_WRAP));
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
private static byte[] base64EncodeUrl(byte[] input) {
byte[] base64 = new String(Base64.encode(input, Base64.NO_WRAP)).getBytes();
for (int i = 0; i < base64.length; ++i) {
switch (base64[i]) {
case '+':
base64[i] = '*';
break;
case '/':
base64[i] = '-';
break;
case '=':
base64[i] = '_';
break;
default:
break;
}
}
return base64;
}
}
package com.ydl.component.rtc.http
import com.ydl.component.rtc.bean.UserSigBean
import com.ydl.component.rtc.bean.UserSigResponse
import com.ydl.ydlcommon.data.http.BaseAPIResponse
import io.reactivex.Observable
interface MDTHttp {
fun getSecret(bean: UserSigResponse): Observable<BaseAPIResponse<UserSigBean>>
}
\ No newline at end of file
package com.ydl.component.rtc.http
import com.google.gson.Gson
import com.ydl.component.rtc.bean.UserSigBean
import com.ydl.component.rtc.bean.UserSigResponse
import com.ydl.ydlcommon.data.http.BaseAPIResponse
import com.ydl.ydlnet.YDLHttpUtils
import io.reactivex.Observable
import okhttp3.MediaType
import okhttp3.RequestBody
class MDTHttpImpl :MDTHttp {
private var mdtService: MDTService? = null
object Holder {
val INSTANCE = MDTHttpImpl()
}
companion object {
fun getInstance(): MDTHttpImpl {
return Holder.INSTANCE
}
}
private fun getMdtService(): MDTService {
if (mdtService == null) {
mdtService = YDLHttpUtils.obtainApi(MDTService::class.java)
}
return mdtService!!
}
//获取登录信息
override fun getSecret(bean: UserSigResponse): Observable<BaseAPIResponse<UserSigBean>> {
val str = Gson().toJson(bean)
val body: RequestBody =
RequestBody.create(MediaType.parse("application/json; charset=utf-8"), str)
return getMdtService().getSecret(body)
}
}
\ No newline at end of file
package com.ydl.component.rtc.http
import com.ydl.component.rtc.bean.UserSigBean
import com.ydl.ydlcommon.base.config.YDL_DOMAIN
import com.ydl.ydlcommon.base.config.YDL_DOMAIN_JAVA
import com.ydl.ydlcommon.data.http.BaseAPIResponse
import io.reactivex.Observable
import okhttp3.RequestBody
import retrofit2.http.Body
import retrofit2.http.Headers
import retrofit2.http.POST
interface MDTService {
//获取用户密钥
@POST("video/secret")
@Headers(
YDL_DOMAIN + YDL_DOMAIN_JAVA,
"Content-Type:application/json"
)
fun getSecret(@Body body: RequestBody): Observable<BaseAPIResponse<UserSigBean>>
}
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/color_blue" />
<corners android:radius="20dp" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#F4F5F9" />
<corners android:radius="26dp" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/color_white" />
<corners android:radius="10dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FF999999" />
<corners android:radius="15dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true">
<shape android:shape="rectangle"
android:useLevel="false">
<solid android:color="#006EFF" />
<corners android:radius="28dp"/>
<padding android:left="5dp" android:right="5dp" android:top="3dp" android:bottom="3dp"/>
</shape>
</item>
<item android:state_enabled="false">
<shape android:shape="rectangle"
android:useLevel="false">
<solid android:color="#0F000000" />
<corners android:radius="28dp"/>
<padding android:left="5dp" android:right="5dp" android:top="3dp" android:bottom="3dp"/>
</shape>
</item>
</selector>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#EFEFEF" />
<corners
android:bottomLeftRadius="2dip"
android:bottomRightRadius="2dip"
android:topLeftRadius="2dip"
android:topRightRadius="2dip" />
<stroke
android:width="5px"
android:color="@color/white" />
</shape>
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_white"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:layout_marginTop="28dp"
android:layout_marginEnd="10dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navigationIcon="@drawable/ic_back">
<TextView
android:id="@+id/toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:singleLine="true"
android:text="@string/app_name"
android:textColor="@color/color_black"
android:textSize="18sp"
android:textStyle="bold" />
<Button
android:id="@+id/btn_ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|center_vertical"
android:background="@android:color/transparent"
android:text="@string/btn_confirm"
android:textColor="@color/black"
android:visibility="gone" />
<ImageButton
android:id="@+id/btn_link"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="right|center_vertical"
android:background="@color/color_transparent"
android:padding="10dp"
android:src="@drawable/ic_question_link" />
</androidx.appcompat.widget.Toolbar>
<LinearLayout
android:id="@+id/ll_list"
android:layout_width="match_parent"
android:layout_height="200dp"
android:orientation="vertical"
android:padding="20dp"
android:visibility="gone"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_added_member"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold" />
<ListView
android:id="@+id/list_member"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_edit"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="10dp"
android:background="@drawable/bg_edit_text"
android:padding="8dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/tv_search"
app:layout_constraintTop_toBottomOf="@+id/ll_list">
<TextView
android:id="@+id/tv_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:text="ID"
android:textColor="@color/color_black"
app:layout_constraintBaseline_toBaselineOf="@id/et_search_user"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/et_search_user"
android:layout_width="210dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:background="@null"
android:hint="@string/search_call_hint"
android:imeOptions="actionSearch"
android:inputType="number"
android:maxLength="11"
android:maxLines="1"
android:singleLine="true"
android:textColor="@color/color_black"
android:textColorHint="@color/text_color_hint"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="@id/cl_edit"
app:layout_constraintLeft_toRightOf="@id/tv_id" />
<ImageView
android:id="@+id/iv_clear_search"
android:layout_width="22dp"
android:layout_height="22dp"
android:background="@drawable/ic_clear_search"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/cl_edit"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/cl_edit" />
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/tv_search"
android:layout_width="76dp"
android:layout_height="38dp"
android:layout_marginEnd="20dp"
android:background="@drawable/bg_btn_search"
android:gravity="center"
android:text="@string/trtccalling_search"
android:textColor="@color/color_white"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="@id/cl_edit"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/cl_edit" />
<TextView
android:id="@+id/line_seperate"
android:layout_width="3dp"
android:layout_height="12dp"
android:layout_marginTop="21dp"
android:layout_marginEnd="22dp"
android:background="@drawable/bg_line_radius"
app:layout_constraintLeft_toLeftOf="@id/cl_edit"
app:layout_constraintTop_toBottomOf="@id/cl_edit" />
<TextView
android:id="@+id/tv_self_userid"
android:layout_width="wrap_content"
android:layout_height="22dp"
android:layout_marginStart="8dp"
android:layout_marginTop="17dp"
android:text="@string/self_userId"
android:textColor="#333333"
android:textSize="14sp"
app:layout_constraintStart_toEndOf="@id/line_seperate"
app:layout_constraintTop_toBottomOf="@id/cl_edit" />
<LinearLayout
android:id="@+id/ll_contract"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:gravity="center_vertical"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="@id/tv_search"
app:layout_constraintStart_toStartOf="@+id/cl_edit"
app:layout_constraintTop_toBottomOf="@+id/tv_self_userid"
tools:visibility="visible">
<com.tencent.qcloud.tuicore.calling.trtccalling.ui.common.RoundCornerImageView
android:id="@+id/img_avatar"
android:layout_width="44dp"
android:layout_height="44dp"
android:src="@drawable/ic_avatar"
app:trtc_radius="15dp" />
<TextView
android:id="@+id/tv_user_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1"
android:textColor="@color/color_black"
android:textSize="16sp" />
<Button
android:id="@+id/btn_start_call"
android:layout_width="56dp"
android:layout_height="26dp"
android:background="@drawable/bg_btn_search"
android:gravity="center"
android:text="@string/trtccalling_start_call"
android:textAllCaps="false"
android:textColor="@color/color_white" />
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_tips"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="120dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/cl_edit">
<ImageView
android:id="@+id/iv_contacts_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ic_contacts_search"
app:layout_constraintBottom_toBottomOf="@id/cl_tips"
app:layout_constraintLeft_toLeftOf="@id/cl_tips"
app:layout_constraintRight_toRightOf="@id/cl_tips"
app:layout_constraintTop_toTopOf="@id/cl_tips" />
<TextView
android:id="@+id/tv_contacts_tips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="11dp"
android:layout_marginTop="10dp"
android:text="@string/tips_search"
android:textColor="@color/color_input_normal"
android:textSize="14sp"
app:layout_constraintLeft_toLeftOf="@id/cl_tips"
app:layout_constraintRight_toRightOf="@id/cl_tips"
app:layout_constraintTop_toBottomOf="@id/iv_contacts_search" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="16dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/item_cl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_item_main_list">
<ImageView
android:id="@+id/img_item"
android:layout_width="170dp"
android:layout_height="136dp"
android:layout_marginStart="14dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_audio_call" />
<TextView
android:id="@+id/tv_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="34dp"
android:layout_marginEnd="10dp"
android:textColor="@color/color_black"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintLeft_toRightOf="@id/img_item"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="10dp"
android:paddingBottom="20dp"
android:textColor="#666666"
android:textSize="14sp"
app:layout_constraintLeft_toRightOf="@id/img_item"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title" />
</androidx.constraintlayout.widget.ConstraintLayout>
<View
android:id="@+id/bottom_line"
android:layout_width="match_parent"
android:layout_height="25dp"
android:visibility="gone" />
</LinearLayout>
<?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"
android:background="@color/color_white">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="120dp"
android:text="@string/welcome_tips"
android:textColor="@color/color_black"
android:textSize="32sp"
app:layout_constraintBottom_toTopOf="@id/cl_edit"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="30dp"
android:background="@drawable/bg_edit_text"
android:padding="16dp"
app:layout_constraintBottom_toTopOf="@id/tv_login"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
<TextView
android:id="@+id/tv_phone_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/user_id"
android:textColor="@color/color_black"
android:textSize="16sp"
app:layout_constraintLeft_toLeftOf="@id/cl_edit"
app:layout_constraintTop_toTopOf="@id/cl_edit" />
<EditText
android:id="@+id/et_userId"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:background="@null"
android:hint="@string/hint_user_id"
android:inputType="number"
android:maxLength="11"
android:maxLines="1"
android:singleLine="true"
android:textColor="@color/color_black"
android:textColorHint="@color/color_input_normal"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="@id/tv_phone_number"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintLeft_toRightOf="@id/tv_phone_number"
app:layout_constraintStart_toEndOf="@+id/tv_phone_number" />
</androidx.constraintlayout.widget.ConstraintLayout>
<Button
android:id="@+id/tv_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:background="@drawable/btn_border"
android:text="@string/btn_login"
android:textColor="@color/color_white"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_white">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="28dp"
android:text="@string/app_title_register"
android:textColor="@color/color_black"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.tencent.qcloud.tuicore.calling.trtccalling.ui.common.RoundCornerImageView
android:id="@+id/iv_user_avatar"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginTop="30dp"
android:layout_centerHorizontal="true"
app:trtc_radius="50dp"
android:src="@mipmap/ic_avatar"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_title"
tools:ignore="MissingConstraints" />
<EditText
android:id="@+id/et_user_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="30dp"
android:layout_marginRight="20dp"
android:background="@drawable/bg_edit_text"
android:hint="@string/app_hint_user_name"
android:maxLines="1"
android:padding="20dp"
android:singleLine="true"
android:textColor="@color/color_black"
android:textColorHint="#BBBBBB"
android:textSize="16sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/iv_user_avatar" />
<TextView
android:id="@+id/tv_tips_user_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="20dp"
android:text="@string/app_tips_user_name"
android:textColor="@color/text_color_hint"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/et_user_name" />
<Button
android:id="@+id/tv_register"
android:layout_width="match_parent"
android:layout_height="52dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="30dp"
android:layout_marginRight="20dp"
android:background="@drawable/btn_border"
android:text="@string/app_title_register"
android:textColor="@color/color_white"
android:textSize="16sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_tips_user_name" />
</androidx.constraintlayout.widget.ConstraintLayout>
......@@ -218,6 +218,14 @@
android:layout_marginRight="10dp"
android:text="我的" />
<Button
android:id="@+id/bt_mdt"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginRight="10dp"
android:text="mdt" />
</LinearLayout>
</LinearLayout>
......
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_white">
<RelativeLayout
android:id="@+id/rl_title"
android:layout_width="match_parent"
android:layout_height="42dp"
android:layout_marginTop="28dp"
android:background="@color/color_white">
<TextView
android:id="@+id/main_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="@string/app_name"
android:textColor="@color/color_black"
android:textSize="18sp"
android:textStyle="bold" />
<ImageView
android:id="@+id/img_logout"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_centerVertical="true"
android:layout_marginStart="15dp"
android:src="@mipmap/ic_avatar"
android:visibility="gone" />
<TextView
android:id="@+id/tv_login_out"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerInParent="true"
android:layout_centerVertical="true"
android:layout_marginRight="20dp"
android:text="@string/app_login_out"
android:textColor="@color/color_black"
android:textSize="16sp" />
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/rl_title"
android:background="@color/color_main_bg"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/main_recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_weight="1" />
</LinearLayout>
</RelativeLayout>
<?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="270dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/bg_item_main_list">
<TextView
android:id="@+id/tv_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:text="aa"
android:textColor="@color/color_main_text"
android:textSize="16sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/view_divide"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="20dp"
android:background="@color/color_line"
app:layout_constraintTop_toBottomOf="@id/tv_message" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_button_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/view_divide">
<Button
android:id="@+id/btn_cancel"
android:layout_width="match_parent"
android:layout_height="44dp"
android:background="@android:color/transparent"
android:gravity="center"
android:text="@string/btn_confirm"
android:textColor="@color/color_blue"
android:textSize="17sp"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<?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="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:padding="5dp">
<com.tencent.qcloud.tuicore.calling.trtccalling.ui.common.RoundCornerImageView
android:id="@+id/img_avatar"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/ic_avatar"
app:trtc_radius="12dp" />
<TextView
android:id="@+id/tv_user_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_weight="1"
android:textColor="@color/color_black"
android:textSize="16sp" />
<Button
android:id="@+id/btn_remove"
android:layout_width="56dp"
android:layout_height="26dp"
android:background="@drawable/bg_btn_search"
android:gravity="center"
android:text="@string/app_remove"
android:textAllCaps="false"
android:textColor="@color/color_white" />
</LinearLayout>
\ No newline at end of file
<?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="270dp"
android:layout_height="142dp"
android:layout_gravity="center"
android:background="@drawable/bg_edit_text">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:text="@string/dialog_log_out"
android:textColor="@color/color_black"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/view_divide"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginBottom="43dp"
android:background="@color/text_color_hint"
app:layout_constraintBottom_toBottomOf="parent" />
<View
android:layout_width="1dp"
android:layout_height="43dp"
android:background="@color/text_color_hint"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_button_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent">
<Button
android:id="@+id/btn_cancel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:text="@string/btn_cancel"
android:textColor="@color/color_blue"
android:textSize="17sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@id/cl_button_panel"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toLeftOf="@id/cl_button_panel"
app:layout_constraintRight_toLeftOf="@+id/btn_sure" />
<Button
android:id="@+id/btn_sure"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:text="@string/btn_confirm"
android:textColor="@color/color_blue"
android:textSize="17sp"
app:layout_constraintBottom_toBottomOf="@id/cl_button_panel"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@id/btn_cancel"
app:layout_constraintRight_toRightOf="@id/cl_button_panel" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
......@@ -9,8 +9,8 @@
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin">
android:paddingLeft="16dp"
android:paddingRight="16dp">
<TextView
android:id="@+id/tv_current_time"
......
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rl_entrance_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#1B1B1B">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="15dp"
android:background="@drawable/common_ic_back" />
<TextView
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="15dp"
android:gravity="center_horizontal"
android:text="TRTC 视频通话示例"
android:textColor="@android:color/white"
android:textSize="20sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_room_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginLeft="60dp"
android:layout_marginTop="100dp"
android:layout_marginRight="60dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请输入房间号(必填项)"
android:textColor="@android:color/white" />
<EditText
android:id="@+id/et_input_room_id"
android:layout_width="match_parent"
android:layout_height="34dp"
android:layout_marginTop="5dp"
android:background="@drawable/common_edit_bg"
android:inputType="number" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/ll_room_info"
android:layout_centerHorizontal="true"
android:layout_marginLeft="60dp"
android:layout_marginTop="30dp"
android:layout_marginRight="60dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请输入用户名(必填项)"
android:textColor="@android:color/white" />
<EditText
android:id="@+id/et_input_username"
android:layout_width="match_parent"
android:layout_height="34dp"
android:layout_marginTop="5dp"
android:background="@drawable/common_edit_bg" />
</LinearLayout>
<Button
android:id="@+id/btn_enter_room"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_margin="60dp"
android:background="@drawable/common_button_bg"
android:text="进入房间"
android:textColor="@android:color/white" />
</RelativeLayout>
\ No newline at end of file
......@@ -12,7 +12,17 @@
<color name="blue">#2196F3</color>
<color name="grey">#9E9E9E</color>
<color name="color_white">#ffffff</color>
<color name="color_black">#000000</color>
<color name="color_transparent">#00000000</color>
<color name="text_color_hint">#BBBBBB</color>
<color name="color_blue">#006EFF</color>
<color name="color_bg_dialog">#66000000</color>
<color name="color_line">#DDDDDD</color>
<color name="color_input_normal">#BBBBBB</color>
<color name="color_input_no_match">#FA585E</color>
<color name="color_main_bg">#F1F3F8</color>
<color name="color_main_text">#333333</color>
<!-- ============ 标准颜色 ============ -->
<!--主题色 - 用于TabBar、突出文字、按钮和icon-->
......
......@@ -4,4 +4,65 @@
<string name="mode_loop">列表循环</string>
<string name="mode_shuffle">随机播放</string>
<string name="mode_one">单曲循环</string>
<string name="app_toast_login_success">登录成功</string>
<string name="app_toast_login_fail">登录IM失败,所有功能不可用[%d]%s</string>
<string name="working">正在运行中</string>
<string name="self_userId">您的userId:</string>
<string name="tips_search">搜索添加已注册用户\n\t\t\t以发起通话</string>
<string name="toast_video_call">视频呼叫:%s</string>
<string name="toast_voice_call">语音呼叫:%s</string>
<string name="toast_not_call_myself">不能呼叫自己</string>
<string name="call_self_format">您的userId: %s</string>
<string name="audio_call">语音通话</string>
<string name="video_call">视频通话</string>
<string name="btn_cancel">取消</string>
<string name="btn_confirm">确定</string>
<string name="search_call_hint">搜索 userId</string>
<string name="user_id">用户名</string>
<string name="hint_user_id">请输入登录的userId</string>
<string name="btn_login">登录</string>
<string name="welcome_tips">欢迎使用\n腾讯云实时音视频</string>
<string name="dialog_log_out">确定要退出登录吗?</string>
<string name="user_sig_expired">您的用户签名信息已过期,请重新登录</string>
<string name="user_id_is_empty">userId 不能为空</string>
<string name="app_title_register">注册</string>
<string name="app_text_user_name">用户名</string>
<string name="app_hint_user_name">请输入用户名</string>
<string name="app_tips_user_name">仅限中文、字母、数字和下划线,2–20个字</string>
<string name="app_toast_register_success_and_logging_in">注册成功</string>
<string name="app_toast_failed_to_set">设置失败: %s</string>
<string name="app_item_multi_audio_call">多人语音通话</string>
<string name="app_item_multi_video_call">多人视频通话</string>
<string name="app_added_member">已添加成员</string>
<string name="app_toast_no_member">无通话成员</string>
<string name="app_toast_multi_call_num_exceed">添加失败,人数超出限制</string>
<string name="app_toast_user_added">用户已添加</string>
<string name="app_tips_search">搜索添加已注册用户\n\t\t\t以发起通话</string>
<string name="app_self_userid">您的ID:</string>
<string name="app_search">搜索</string>
<string name="app_start_call">呼叫</string>
<string name="app_user_not_exist">用户不存在</string>
<string name="app_add">添加</string>
<string name="app_remove">移除</string>
<string name="app_tv_voice_call_tips">丢包率>70%可正常语音通话</string>
<string name="app_tv_video_call_tips">丢包率>50%可正常视频通话</string>
<string name="app_login_out">退出登录</string>
<string name="app_permission_hint">为了应用在后台时响应通话请求,请到设置中打开应用“后台拉起界面”权限</string>
<!--自定义随机登录名-->
<string name="app_custom_name_1">路飞</string>
<string name="app_custom_name_2">山治</string>
<string name="app_custom_name_3">娜美</string>
<string name="app_custom_name_4">乌索普</string>
<string name="app_custom_name_5">香克斯</string>
<string name="app_custom_name_6">弗兰奇</string>
<string name="app_custom_name_7">罗宾</string>
<string name="app_custom_name_8">钢铁侠</string>
<string name="app_custom_name_9">蜘蛛侠</string>
<string name="app_custom_name_10">乔巴</string>
<string name="app_custom_name_11">鸣人</string>
<string name="app_custom_name_12">艾斯</string>
</resources>
<resources>
<!-- Base application theme. -->
<style name="logoutDialogStyle" parent="@android:style/Theme.Holo.Dialog">
<item name="android:windowIsFloating">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowCloseOnTouchOutside">true</item>
<item name="android:windowBackground">@color/color_bg_dialog</item>
<item name="android:windowSoftInputMode">adjustResize</item>
</style>
</resources>
{
"tpns": {
"access_id": "",
"access_key": ""
},
"com.tencent.trtc": {
"channel": {
"enable": true,
"xiaomi": {
"app_id": "",
"app_key": ""
},
"vivo": {
"app_id": "",
"app_key": ""
},
"oppo": {
"app_id": "",
"app_key": ""
},
"meizu": {
"app_id": "",
"app_key": ""
}
}
},
"debug": true,
"version": "1.3.2.1-release",
"upgrade": false
}
\ No newline at end of file
......@@ -32,8 +32,11 @@ ext {
"m-dynamic-api" : "0.0.3.71",
//-------------- 功能组件 --------------
//mdt 组件
"ydl-tuicore" : "0.0.21",
// "m-tuicore-ydl" : "0.0.10",
//第一步
"ydl-platform" : "0.0.40.89",
"ydl-platform" : "0.0.40.96",
//第二步 若干
"ydl-webview" : "0.0.38.61",
......@@ -44,8 +47,8 @@ ext {
//以下 几乎不会动
"router" : "0.0.1",
"ydl-net" : "0.0.3.92",
"ydl-utils" : "0.0.3.2",
"ydl-net" : "0.0.3.93",
"ydl-utils" : "0.0.3.3",
]
ydl_app = [
appName : "壹点灵心理咨询",
......@@ -114,9 +117,11 @@ ext {
"m-im-api" : "0.0.12.23",
"m-dynamic-api" : "0.0.3.71",
//-------------- 功能组件 --------------
//mdt组件
"ydl-tuicore" : "0.0.9",
"m-tuicore-ydl" : "0.0.10",
//第一步
"ydl-platform" : "0.0.40.89",
"ydl-platform" : "0.0.40.96",
//第二步 若干
"ydl-webview" : "0.0.38.61",
......@@ -127,8 +132,8 @@ ext {
//以下 几乎不会动
"router" : "0.0.1",
"ydl-net" : "0.0.3.92",
"ydl-utils" : "0.0.3.1",
"ydl-net" : "0.0.3.93",
"ydl-utils" : "0.0.3.3",
]
dependencies = [
......@@ -237,7 +242,7 @@ ext {
"androidanimations" : "com.daimajia.androidanimations:library:2.3@aar",
//友盟统计
"umeng-common" : "com.umeng.umsdk:common:9.3.8",
"umeng-asms" :"com.umeng.umsdk:asms:1.2.2",
"umeng-asms" : "com.umeng.umsdk:asms:1.2.2",
//友盟社会化分享
"umeng-share-core" : "com.umeng.umsdk:share-core:7.1.4",
"umeng-share-qq" : "com.umeng.umsdk:share-qq:7.1.4",
......@@ -282,7 +287,8 @@ ext {
//基础组件 <<--- 先发这个,发完改这里的版本号
"ydl-platform" : "com.ydl:ydl-platform:${ydlCompileVersion["ydl-platform"]}@aar",
"ydl-tuicore" : "com.ydl:ydl-tuicore:${ydlCompileVersion["ydl-tuicore"]}@aar",
"m-tuicore-ydl" : "com.ydl:m-tuicore-ydl:${ydlCompileVersion["m-tuicore-ydl"]}@aar",
//功能组件 <<--- 再发这些,发完改这里的版本号
"ydl-webview" : "com.ydl:ydl-webview:${ydlCompileVersion["ydl-webview"]}@aar",
"ydl-media" : "com.ydl:ydl-media:${ydlCompileVersion["ydl-media"]}@aar",
......
......@@ -75,7 +75,7 @@ dependencies {
kapt "com.alibaba:arouter-compiler:$arouter_compiler"
api "com.alibaba:arouter-api:$arouter_api"
api ('com.ydl:ydl-av:1.3.8@aar'){
api ('com.ydl:ydl-av:1.3.4@aar'){
transitive = true
}
......
......@@ -135,7 +135,8 @@ public class DynamicApiUtils {
return YDLHttpUtils.Companion.obtainApi(NetApiStore.class).reportWorry(getMaps(list));
}
//发布动态
//发布
// 动态
public static Observable<BaseResponse<PublishTrendResult>> publishTrend(Command.PublishTrend cmd, File... files) {
Map<String, RequestBody> map = NetworkParamsUtils.getFileMaps(cmd, "FILE", files);
return YDLHttpUtils.Companion.obtainApi(NetApiStore.class).publishTrend(map);
......
package com.yidianling.im.bean;
import com.ydl.ydlcommon.data.http.BaseCommand;
public class TeamAlreadyReadBean extends BaseCommand {
public String tid;
public String uid;
public TeamAlreadyReadBean(String tid, String uid) {
this.tid = tid;
this.uid = uid;
}
}
package com.yidianling.im.event
class ChatGroupStatusEvent()
\ No newline at end of file
......@@ -70,6 +70,7 @@ interface ImApi {
@POST("consult/get-expert")
fun getExpert(@FieldMap params: Map<String, String>): Observable<BaseResponse<IMExpertBuild>>
//以下接口为消息改版后新加
//私聊 获取各消息未读数
@GET("chat/getNotifyCountMessage")
......
......@@ -50,4 +50,5 @@ interface ImHttp {
fun getInteractMessage(param: InteractMessageParam): Observable<BaseAPIResponse<InteractBean>>
fun getUnreadMessage(param: UnreadParam): Observable<BaseAPIResponse<UnreadMessageBean>>
}
\ No newline at end of file
......@@ -37,6 +37,11 @@ interface ImRetrofitApi {
@POST("consult/get-expert")
fun getExpert(@FieldMap params: Map<String, String>): Observable<BaseResponse<IMExpertBuild>>
//群聊 群聊Ait艾特符号已读
@POST("message/chatRoom/readApnsMessage")
@Headers(YDL_DOMAIN + YDL_DOMAIN_JAVA)
fun teamChatALreadyRead(@Body params: Map<String, String>): Observable<BaseResponse<Any>>
//获取用户的状态(用户、专家、助理)
@GET("user/userType")
......
......@@ -408,7 +408,9 @@ public class SessionHelper {
ArrayList<BaseAction> actions = new ArrayList<>();
actions.add(new ImageAction());
actions.add(new VideoAction());
actions.add(avChatAction);
//去掉群聊的视频通话按钮
// actions.add(avChatAction);
SessionTeamCustomization.SessionTeamCustomListener listener = new SessionTeamCustomization.SessionTeamCustomListener() {
@Override
......
......@@ -18,7 +18,6 @@ import com.ydl.ydlcommon.bean.StatusBarOptions
import com.ydl.ydlcommon.data.http.RxUtils
import com.ydl.ydlcommon.utils.actionutil.ActionCountUtils
import com.ydl.ydlcommon.utils.actionutil.ActionCountUtils.Companion.count
import com.yidianling.common.tools.LogUtil
import com.yidianling.common.tools.ToastUtil
import com.yidianling.im.R
import com.yidianling.im.api.event.ImLogoutEvent
......@@ -41,6 +40,7 @@ import com.yidianling.im.ui.page.fragment.bean.UnreadMessageBean
import com.yidianling.im.ui.page.popupWindow.ChatSettingPopupWindow
import com.yidianling.im.ui.param.ClearMessageParam
import com.yidianling.im.ui.param.UnreadParam
import com.yidianling.uikit.api.NimUIKit
import de.greenrobot.event.EventBus
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
......@@ -354,6 +354,7 @@ class NewMultiMessageFragment : BaseFragment() {
} else {
ToastUtil.toastShort("请登录后再试")
}
NimUIKit.startYDLChatting(context,"4597318766",SessionTypeEnum.Team,null,null,null)
}
}
/**
......
......@@ -7,12 +7,17 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.jcodecraeer.xrecyclerview.CustomFooterViewCallBack
import com.jcodecraeer.xrecyclerview.XRecyclerView
import com.ydl.ydlcommon.base.BaseFragment
import com.ydl.ydlcommon.data.http.BaseResponse
import com.ydl.ydlcommon.data.http.RxUtils
import com.ydl.ydlcommon.utils.NetworkParamsUtils
import com.ydl.ydlcommon.utils.NetworkParamsUtils.getMaps
import com.yidianling.common.tools.ToastUtil
import com.yidianling.im.R
import com.yidianling.im.bean.TeamAlreadyReadBean
import com.yidianling.im.event.MessageListRefreshEvent
import com.yidianling.im.helper.MsgReceiveHelper
import com.yidianling.im.http.ImHttpImpl
import com.yidianling.im.http.ImRetrofitApi
import com.yidianling.im.router.ImIn
import com.yidianling.im.ui.page.fragment.adapter.ChatAdapter
import com.yidianling.im.ui.page.fragment.bean.ChatItemBean
......@@ -21,6 +26,8 @@ import com.yidianling.im.ui.page.fragment.view.ChatFooterItemView
import com.yidianling.im.ui.page.widget.ChatUnusualView
import com.yidianling.im.ui.param.ChatParam
import de.greenrobot.event.EventBus
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.im_chat_fragment_layout.*
/**
......@@ -87,7 +94,7 @@ class ChatFragment : BaseFragment(), XRecyclerView.LoadingListener {
if (ImIn.getUserInfo()?.uid != "0") {
var dis = ImHttpImpl.getInstance()
.getAllChatMessage(ChatParam("${ImIn.getUserInfo()?.uid}", "${selectType}"))
.getAllChatMessage(ChatParam("${ImIn.getUserInfo()?.uid}", "${selectType}","1"))
.compose(RxUtils.applySchedulers(this))
.compose<ChatModelBean>(RxUtils.resultJavaData())
.subscribe({ it ->
......@@ -224,6 +231,12 @@ class ChatFragment : BaseFragment(), XRecyclerView.LoadingListener {
getChatMessageData()
}
})
chatAdapter?.setChatAitReadlistener(object :ChatAdapter.ChatAitAlreadyRead{
override fun alreadyReadAit(tid:String) {
//群聊已读消息
TeamAlreadyRead(tid)
}
})
chat_recyclerview.layoutManager = LinearLayoutManager(context)
chat_recyclerview.adapter = chatAdapter
chat_recyclerview.setLoadingListener(this)
......@@ -241,6 +254,20 @@ class ChatFragment : BaseFragment(), XRecyclerView.LoadingListener {
})
}
private fun TeamAlreadyRead(tid: String) {
val cmd = TeamAlreadyReadBean(tid, ImIn.getUserInfo()?.uid.toString())
val disposable =
ImRetrofitApi.getImJavaApi().teamChatALreadyRead(getMaps(cmd))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ resp: BaseResponse<Any> ->
}
) { throwable: Throwable ->
}
}
override fun onResume() {
super.onResume()
resetPageShow()
......
......@@ -15,6 +15,7 @@ import com.ydl.ydlcommon.data.http.RxUtils
import com.ydl.ydlcommon.utils.log.LogHelper
import com.ydl.ydlcommon.utils.remind.ToastHelper
import com.ydl.ydlcommon.view.ListNoCancelDialog
import com.yidianling.common.tools.ToastUtil
import com.yidianling.im.api.param.RmHistoryParam
import com.yidianling.im.api.param.RmTalkParam
import com.yidianling.im.api.param.TopMessageParam
......@@ -23,11 +24,15 @@ import com.yidianling.im.event.UpdateTabUnreadNumEvent
import com.yidianling.im.helper.IMChatUtil
import com.yidianling.im.helper.MsgReceiveHelper
import com.yidianling.im.http.ImHttpImpl
import com.yidianling.im.router.ImIn
import com.yidianling.im.session.SessionHelper
import com.yidianling.im.ui.page.fragment.bean.ChatItemBean
import com.yidianling.im.ui.page.fragment.bean.ChatModelBean
import com.yidianling.im.ui.page.fragment.view.ChatItemView
import com.yidianling.im.ui.page.fragment.view.ChatTimeItemView
import com.yidianling.im.ui.param.ChatParam
import de.greenrobot.event.EventBus
import kotlinx.android.synthetic.main.im_chat_fragment_layout.*
/**
* 互动列表适配器
......@@ -63,9 +68,15 @@ class ChatAdapter(var context: Context, private var mList: ArrayList<ChatItemBea
P2PCustomActionHandlerImpl("4108805", "课程小助手-壹壹", "4108805"))
}else {
// IMUtil.startChat(context as AppCompatActivity, mList[position].toUid.toString(), 0, 0, null, 0, true)
if (mList[position].chat_type==2){//群聊
mChatListener?.alreadyReadAit(mList[position].toUid.toString())
SessionHelper.startTeamSession(context,mList[position].toUid.toString())
}else{//单聊
IMChatUtil.startChat(context as AppCompatActivity, mList[position])
}
}
}
holder.view.setOnLongClickListener {
......@@ -214,6 +225,16 @@ class ChatAdapter(var context: Context, private var mList: ArrayList<ChatItemBea
fun onRefresh() //刷新聊天列表
}
private var mChatListener: ChatAitAlreadyRead? = null
fun setChatAitReadlistener(mChatListener: ChatAitAlreadyRead) {
this.mChatListener = mChatListener
}
interface ChatAitAlreadyRead {
fun alreadyReadAit( tid:String) //群聊艾特符号
}
/**
* 互动列表正常item的holder
*/
......
......@@ -20,7 +20,7 @@ class ChatItemBean(
var timestamp: Long = 0.toLong(),
var title: String = "",
var toName: String = "",
var toUid: Int = 0,
var toUid: Long = 0,
var type: Int = 0,//私聊群聊type=3
var utype: Int = 0,
var timeStr: String = "",
......@@ -28,5 +28,6 @@ class ChatItemBean(
var doctorTitle: String = "",
var isThreeItem: Boolean = false, //是否是三周前时间展示item
var listenOrderStatus: Int = 0, // 倾诉状态
var orderStatus: Int = 0 //咨询状态
var orderStatus: Int = 0 ,//咨询状态
var noReadAtContent:String?=""
)
\ No newline at end of file
......@@ -5,10 +5,10 @@ import android.text.Html
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.RelativeLayout
import com.netease.nimlib.sdk.NIMClient
import com.netease.nimlib.sdk.team.TeamService
import com.ydl.ydl_image.module.GlideApp
import com.yidianling.im.R
import com.yidianling.im.helper.MsgReceiveHelper
import com.yidianling.im.preference.ImTempData
import com.yidianling.im.ui.page.fragment.bean.ChatItemBean
import kotlinx.android.synthetic.main.im_chat_item_view.view.*
......@@ -73,10 +73,27 @@ class ChatItemView(mContext: Context) : LinearLayout(mContext) {
bean.toUid.toString()
)
chat_message_content.setText(Html.fromHtml(th))
}else if (!bean.noReadAtContent.isNullOrEmpty()){
var th = "<font color='#FF7766' charset='utf-8'>[有人@我]</font> " + bean.content;
chat_message_content.setText(Html.fromHtml(th));
}else {
chat_message_content.text = bean.content
}
if (bean.is_top == 1) {
chat_global_ll.setBackgroundResource(R.drawable.im_chat_is_top_bg)
} else {
chat_global_ll.setBackgroundResource(0)
}
//如果是群聊 根据免打扰状态判断逻辑
if (bean.chat_type==2){
val notifyType = NIMClient.getService(TeamService::class.java)
.queryTeamBlock(bean.toUid.toString()).messageNotifyType.value // 群消息提醒
if (notifyType==0){
//有消息提醒
not_disturb.visibility=View.GONE
if (bean.unReadNum > 99) {
chat_message_unread_num.visibility = View.VISIBLE
chat_message_unread_num.text = "99+"
......@@ -86,11 +103,30 @@ class ChatItemView(mContext: Context) : LinearLayout(mContext) {
} else {
chat_message_unread_num.visibility = View.GONE
}
if (bean.is_top == 1) {
chat_global_ll.setBackgroundResource(R.drawable.im_chat_is_top_bg)
}else{
val layoutParams: ViewGroup.LayoutParams = chat_message_unread_num.getLayoutParams()
layoutParams.height = 36
layoutParams.width = 36
chat_message_unread_num.setLayoutParams(layoutParams)
not_disturb.visibility=View.VISIBLE
if (bean.unReadNum > 0){
chat_message_unread_num.visibility=View.VISIBLE
chat_message_unread_num.text=""
}else{
chat_message_unread_num.visibility = View.GONE
}
}
}else{
if (bean.unReadNum > 99) {
chat_message_unread_num.visibility = View.VISIBLE
chat_message_unread_num.text = "99+"
} else if (bean.unReadNum > 0) {
chat_message_unread_num.visibility = View.VISIBLE
chat_message_unread_num.text = "${bean.unReadNum}"
} else {
chat_global_ll.setBackgroundResource(0)
chat_message_unread_num.visibility = View.GONE
}
not_disturb.visibility=View.GONE
}
}
......
......@@ -4,4 +4,4 @@ package com.yidianling.im.ui.param
* 消息列表请求参数 selectTab:0(全部),1(服务中),2(服务过)
* Created by xj on 2019/10/21.
*/
data class ChatParam(var uid: String, var selectType: String)
\ No newline at end of file
data class ChatParam(var uid: String, var selectType: String,var includeGroupChat:String="1")
\ No newline at end of file
......@@ -176,7 +176,8 @@ public class AitManager implements TextWatcher {
if (s.toString().equals("@")) {
// 启动@联系人界面
if (!TextUtils.isEmpty(tid) ) {
AitContactSelectorActivity.start(context, tid);
//暂时注释艾特相关群成员功能
// AitContactSelectorActivity.start(context, tid);
}
}
aitContactsModel.onInsertText(start, s.toString());
......
......@@ -167,9 +167,11 @@ public class YDLP2PMessageActivity extends YDLBaseMessageActivity {
//读取未发送的临时消息
if (ActionHandlerStorage.getL(sessionId) != null) {
if (messageFragment.getInputPanel().getInputContent() == null || messageFragment.getInputPanel().getInputContent().equals("")) {
if (messageFragment.getInputPanel()==null||messageFragment.getInputPanel().getInputContent() == null || messageFragment.getInputPanel().getInputContent().equals("")) {
if (messageFragment.getInputPanel()!=null){
messageFragment.getInputPanel().setInputContent(ActionHandlerStorage.getL(sessionId).getImTempData(sessionId));
}
}
if (ActionHandlerStorage.needLoadNewMsg) {
((BaseFetchLoadAdapter.RequestFetchMoreListener) messageFragment.getMessageListPanelEx().getMessageLoder(null)).onFetchMoreRequested();
ActionHandlerStorage.needLoadNewMsg = false;
......
......@@ -216,7 +216,9 @@ public class YDLTeamMessageActivity extends YDLBaseMessageActivity {
team = d;
fragment.setTeam(team);
setTitle(team == null ? sessionId : team.getName() + "(" + team.getMemberCount() + "人)");
//暂时去掉群聊人数标题
// setTitle(team == null ? sessionId : team.getName() + "(" + team.getMemberCount() + "人)");
setTitle(team == null ? sessionId : team.getName() );
invalidTeamTipText.setText(team.getType() == TeamTypeEnum.Normal ? R.string.im_normal_team_invalid_tip : R.string.im_team_invalid_tip);
invalidTeamTipView.setVisibility(team.isMyTeam() ? View.GONE : View.VISIBLE);
......@@ -300,7 +302,7 @@ public class YDLTeamMessageActivity extends YDLBaseMessageActivity {
};
@Override
protected YDLMessageFragment fragment() {
protected YDLTeamMessageFragment fragment() {
// 添加fragment
Bundle arguments = getIntent().getExtras();
arguments.putSerializable(Extras.EXTRA_TYPE, SessionTypeEnum.Team);
......
......@@ -4,9 +4,13 @@ import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
......@@ -22,12 +26,10 @@ import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.recyclerview.widget.RecyclerView;
import com.alibaba.fastjson.JSON;
import com.google.gson.Gson;
import com.netease.nimlib.sdk.NIMClient;
import com.netease.nimlib.sdk.Observer;
......@@ -36,7 +38,6 @@ import com.netease.nimlib.sdk.ResponseCode;
import com.netease.nimlib.sdk.msg.MessageBuilder;
import com.netease.nimlib.sdk.msg.MsgService;
import com.netease.nimlib.sdk.msg.MsgServiceObserve;
import com.netease.nimlib.sdk.msg.attachment.MsgAttachment;
import com.netease.nimlib.sdk.msg.constant.MsgStatusEnum;
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
import com.netease.nimlib.sdk.msg.model.CustomMessageConfig;
......@@ -47,20 +48,28 @@ import com.netease.nimlib.sdk.uinfo.model.NimUserInfo;
import com.ydl.webview.H5Params;
import com.ydl.webview.NewH5Activity;
import com.ydl.ydl_image.module.GlideApp;
import com.ydl.ydlcommon.base.config.HttpConfig;
import com.ydl.ydlcommon.data.PlatformDataManager;
import com.ydl.ydlcommon.data.http.RxUtils;
import com.ydl.ydlcommon.modular.ModularServiceManager;
import com.ydl.ydlcommon.ui.LoadingDialogFragment;
import com.ydl.ydlcommon.utils.AnimUtils;
import com.ydl.ydlcommon.utils.LogUtil;
import com.ydl.ydlcommon.utils.NetworkParamsUtils;
import com.ydl.ydlcommon.utils.SharedPreferencesEditor;
import com.ydl.ydlcommon.utils.YdlBuryPointUtil;
import com.ydl.ydlcommon.utils.actionutil.ActionCountUtils;
import com.ydl.ydlcommon.utils.log.AliYunLogConfig;
import com.ydl.ydlcommon.utils.log.AliYunRichLogsHelper;
import com.ydl.ydlcommon.utils.log.LogHelper;
import com.ydl.ydlcommon.utils.remind.HttpErrorUtils;
import com.ydl.ydlcommon.view.CircleImageView;
import com.ydl.ydlcommon.view.dialog.CommonDialog;
import com.ydl.ydlcommon.view.dialog.ListDialog;
import com.yidianling.common.tools.ToastUtil;
import com.yidianling.im.R;
import com.yidianling.im.bean.RemoveHistory;
import com.yidianling.im.config.constants.ImConstants;
import com.yidianling.im.event.MultipleAnswerBean;
import com.yidianling.im.event.MultipleSelectedEvent;
import com.yidianling.im.helper.IMChatUtil;
......@@ -86,6 +95,7 @@ import com.yidianling.uikit.api.NimUIKitImpl;
import com.yidianling.uikit.business.ait.AitManager;
import com.yidianling.uikit.business.session.activity.YDLBaseMessageActivity;
import com.yidianling.uikit.business.session.helper.ChatStatusCacheHelper;
import com.yidianling.uikit.business.session.helper.MessageListPanelHelper;
import com.yidianling.uikit.business.session.module.input.InputPanel;
import com.yidianling.uikit.business.session.module.list.MessageListPanelEx;
import com.yidianling.uikit.business.session.view.ChatPrivateTips;
......@@ -152,7 +162,7 @@ public class YDLMessageFragment extends TFragment implements ModuleProxy {
private int rvPaddingTop;
private RelativeLayout rl_contain;
private boolean initHeightFinish;
public TitleBarBottom titleBar;
public InputPanel getInputPanel() {
return inputPanel;
}
......@@ -197,8 +207,7 @@ public class YDLMessageFragment extends TFragment implements ModuleProxy {
private RelativeLayout constraint_ll;
private LinearLayout ll_info_detail;
private RelativeLayout rela_zixun;
protected RelativeLayout rela_zixun;
private ValueAnimator anim_out;
private ObjectAnimator sourceLayoutAnim;
private ValueAnimator anim_in;
......@@ -245,9 +254,13 @@ public class YDLMessageFragment extends TFragment implements ModuleProxy {
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
parseIntent();
TitleBarBottom titleBar = ((YDLBaseMessageActivity) getActivity()).getTitleBarBottom();
titleBar = ((YDLBaseMessageActivity) getActivity()).getTitleBarBottom();
titleBar.setTitleLeftDraw(getResources().getDrawable(R.drawable.loading_01));
titleBar.setTitle("正在连接中...");
if (sessionType==SessionTypeEnum.Team){
titleBar.setRightIcon(getContext().getDrawable(R.drawable.platform_common_more));
}
fl_container = rootView.findViewById(R.id.message_activity_list_view_container);
v_chattips = rootView.findViewById(R.id.v_chattips);
lin_actions = rootView.findViewById(R.id.lin_actions);
......@@ -280,13 +293,13 @@ public class YDLMessageFragment extends TFragment implements ModuleProxy {
question_multiple = rootView.findViewById(R.id.question_multiple);
//做灵犀2.0 去掉常用语逻辑
//rl_common_question_enter.setVisibility(ActionHandlerStorage.getL(sessionId) != null && ActionHandlerStorage.getL(sessionId).getUserType() == 3 ? View.VISIBLE : View.GONE);
if (ActionHandlerStorage.getL(sessionId).getUserType() != 2) {
if (null!=ActionHandlerStorage.getL(sessionId)&&ActionHandlerStorage.getL(sessionId).getUserType() != 2) {
if (null != getActivity() && null != rela_zixun) {
rela_zixun.setVisibility(View.GONE);
}
}
if (ActionHandlerStorage.getL(sessionId).isNotPrepare()) {
if (null!=ActionHandlerStorage.getL(sessionId)&&ActionHandlerStorage.getL(sessionId).isNotPrepare()) {
IMChatUtil.INSTANCE.prepareChatData((AppCompatActivity) getActivity(), sessionId, (expertInfo) -> {
String toUid = expertInfo.shareData.toUid;
IP2PCustomActionHandler handler = ActionHandlerStorage.getL(sessionId);
......@@ -303,6 +316,12 @@ public class YDLMessageFragment extends TFragment implements ModuleProxy {
} else {
initView();
}
//如果是群聊
if (SessionTypeEnum.Team==sessionType){
rela_zixun.setVisibility(View.GONE);
titleBar.setTitleRightDraw(null);
}
}
@SuppressLint("CheckResult")
......@@ -348,7 +367,9 @@ public class YDLMessageFragment extends TFragment implements ModuleProxy {
} else {
titleBar.setTitleRightDraw(getResources().getDrawable(R.drawable.im_erduoxiaolv));
}
if (ActionHandlerStorage.getL(sessionId)!=null){
titleBar.setTitle(ActionHandlerStorage.getL(sessionId).getInfo().name);
}
// 初始化顶部专家信息栏
if (ActionHandlerStorage.getL(sessionId) != null && ActionHandlerStorage.getL(sessionId).getUserType() == 2) {
top_expert_info_cl.setVisibility(View.VISIBLE);
......@@ -398,7 +419,7 @@ public class YDLMessageFragment extends TFragment implements ModuleProxy {
//初始化私聊页面配置
initDefaultConfig();
if (ActionHandlerStorage.getL(sessionId).getInfo().doctorId != null){
if (null!=ActionHandlerStorage.getL(sessionId)&&ActionHandlerStorage.getL(sessionId).getInfo().doctorId != null){
// 获取专家是否在繁忙状态
ServiceImpl.Companion.getInstance().queryDoctorIsBusy(ActionHandlerStorage.getL(sessionId).getInfo().doctorId)
.subscribeOn(Schedulers.io())
......@@ -410,7 +431,17 @@ public class YDLMessageFragment extends TFragment implements ModuleProxy {
}
}
/**
* 是否隐藏输入框相关控件
*/
public void setGoneInput(boolean isGone){
if (isGone){
inputPanel.messageInputBar.setVisibility(View.GONE);
inputPanel.hideInputMethod();
}else {
inputPanel.messageInputBar.setVisibility(View.VISIBLE);
}
}
@SuppressLint("CheckResult")
private void initDefaultConfig() {
ServiceImpl.Companion.getInstance().getChatViewConfig()
......
package com.yidianling.uikit.business.session.fragment;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.netease.nimlib.sdk.NIMClient;
import com.netease.nimlib.sdk.RequestCallback;
import com.netease.nimlib.sdk.msg.MsgService;
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
import com.netease.nimlib.sdk.msg.model.IMMessage;
import com.netease.nimlib.sdk.team.TeamService;
import com.netease.nimlib.sdk.team.constant.TeamMemberType;
import com.netease.nimlib.sdk.team.constant.TeamMessageNotifyTypeEnum;
import com.netease.nimlib.sdk.team.model.Team;
import com.netease.nimlib.sdk.team.model.TeamMember;
import com.ydl.ydlcommon.data.http.RxUtils;
import com.ydl.ydlcommon.ui.LoadingDialogFragment;
import com.ydl.ydlcommon.utils.NetworkParamsUtils;
import com.ydl.ydlcommon.utils.log.LogHelper;
import com.ydl.ydlcommon.utils.remind.HttpErrorUtils;
import com.ydl.ydlcommon.view.dialog.CommonDialog;
import com.ydl.ydlcommon.view.dialog.ListDialog;
import com.yidianling.common.tools.ToastUtil;
import com.yidianling.im.R;
import com.yidianling.im.bean.RemoveHistory;
import com.yidianling.im.event.ChatGroupStatusEvent;
import com.yidianling.im.http.ImRetrofitApi;
import com.yidianling.im.router.ImIn;
import com.yidianling.nimbase.impl.cache.TeamDataCache;
import com.yidianling.uikit.api.NimUIKit;
import com.yidianling.uikit.business.session.helper.MessageListPanelHelper;
import com.yidianling.uikit.custom.widget.TitleBarBottom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import de.greenrobot.event.EventBus;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
/**
* Created by zhoujianghua on 2015/9/10.
*/
......@@ -21,6 +54,7 @@ public class YDLTeamMessageFragment extends YDLMessageFragment {
private Team team;
@Override
public boolean isAllowSendMessage(IMMessage message) {
TeamMember teamMember= TeamDataCache.getInstance().getTeamMember(team.getId(), NimUIKit.getAccount());
......@@ -35,6 +69,12 @@ public class YDLTeamMessageFragment extends YDLMessageFragment {
}
@Override
public void onResume() {
super.onResume();
getChatGroupMute();
}
@Override
public boolean sendMessage(IMMessage message) {
if (!isAllowSendMessage(message)) {
return false;
......@@ -49,9 +89,129 @@ public class YDLTeamMessageFragment extends YDLMessageFragment {
return super.sendMessage(message);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
titleBar.setOnRightTextClick(new TitleBarBottom.OnTitleBarTextClick() {
@Override
public void onClick(View view, boolean isActive) {
List<String> list = new ArrayList<>();
int notifyType = NIMClient.getService(TeamService.class).queryTeamBlock(sessionId).getMessageNotifyType().getValue(); // 群消息提醒
// if (ImConstants.KEFUXIAOYI.equals(toChatUsername) || "4108805".equals(toChatUsername)) {
// list.add("历史聊天记录");
// list.add("客服热线");
// } else {
// if (notifyType==0){
// list.add("关闭群消息提醒");
// }else{
// list.add("开启群消息提醒");
// }
list.add("投诉反馈");
//
// list.add("历史聊天记录");
// list.add("删除聊天记录");
// }
list.add("删除聊天记录");
ListDialog.Builder dialog = new ListDialog.Builder(getContext(), list, 0, team.getName());
list.add("取消");
dialog.create().show();
dialog.SetOnItemClickLister(new ListDialog.Builder.OnItemClickLister() {
@Override
public void onItemClick(Dialog dialog, View view, int position) {
LogHelper.Companion.getInstance().writeLogSync(String.format("聊天界面:%s", list.get(position)));
switch (list.get(position)) {
case "开启群消息提醒":
case "关闭群消息提醒":
OpenCloseTeamMute(notifyType);
break;
case "投诉反馈":
ImIn.INSTANCE.feedBackIntent((Activity) getContext());
break;
case "返回首页":
ImIn.INSTANCE.mainIntent(getContext(), 0);
break;
case "客服热线":
// showCallDialog();
break;
case "历史聊天记录":
// historyMsg();
break;
case "删除聊天记录":
deleteChatHistory();
break;
case "ta的主页":
// showUserHome();
break;
case "取消":
break;
}
dialog.dismiss();
}
@Override
public void onItemLongClick(Dialog dialog, View view, int position) {
}
});
}
});
}
private void OpenCloseTeamMute(int notifyType) {
TeamMessageNotifyTypeEnum type = TeamMessageNotifyTypeEnum.All;
if (notifyType ==0){
type = TeamMessageNotifyTypeEnum.Mute;
}
NIMClient.getService(TeamService.class).muteTeam(team.getId(), type).setCallback(new RequestCallback<Void>() {
@Override
public void onSuccess(Void param) {
ToastUtil.toastShort("成功");
// 设置成功
}
@Override
public void onFailed(int code) {
ToastUtil.toastShort(code+"");
// 设置失败
}
@Override
public void onException(Throwable exception) {
// 错误
}
});
}
public void onEventMainThread(ChatGroupStatusEvent event){
getChatGroupMute();
}
//获取群聊是否全员禁言
private void getChatGroupMute(){
boolean mute = NIMClient.getService(TeamService.class).queryTeamBlock(sessionId).isAllMute();
setGoneInput(mute);
}
public void setTeam(Team team) {
Log.e("hzs","-------------setTeam------------TeammessageFragment");
this.team = team;
}
/**
* 删除聊天记录
*/
private void deleteChatHistory() {
CommonDialog dialog = CommonDialog.create(getContext());
dialog.setMessage("确定删除与ta的聊天记录?");
dialog.setCancelAble(true);
dialog.setLeftOnclick("再考虑下", v -> dialog.dismiss());
dialog.setRightClick("立即删除", v -> {
ToastUtil.toastShort("聊天记录已删除");
NIMClient.getService(MsgService.class).clearServerHistory(team.getId(),SessionTypeEnum.Team);
MessageListPanelHelper.getInstance().notifyClearMessages(team.getId());
});
dialog.show();
}
}
\ No newline at end of file
......@@ -14,12 +14,15 @@ import com.netease.nimlib.sdk.team.model.MuteMemberAttachment;
import com.netease.nimlib.sdk.team.model.Team;
import com.netease.nimlib.sdk.team.model.UpdateTeamAttachment;
import com.yidianling.im.R;
import com.yidianling.im.event.ChatGroupStatusEvent;
import com.yidianling.uikit.api.NimUIKit;
import com.yidianling.uikit.business.team.helper.TeamHelper;
import java.util.List;
import java.util.Map;
import de.greenrobot.event.EventBus;
/**
* 系统消息描述文本构造器。主要是将各个系统消息转换为显示的文本内容。<br>
* Created by huangjun on 2015/3/11.
......@@ -165,7 +168,7 @@ public class TeamNotificationHelper {
StringBuilder sb = new StringBuilder();
for (Map.Entry<TeamFieldEnum, Object> field : a.getUpdatedFields().entrySet()) {
if (field.getKey() == TeamFieldEnum.Name) {
sb.append("名称被更新为 " + field.getValue());
sb.append("群名称修改为" +"\""+ field.getValue()+"\"");
} else if (field.getKey() == TeamFieldEnum.Introduce) {
sb.append("群介绍被更新为 " + field.getValue());
} else if (field.getKey() == TeamFieldEnum.Announcement) {
......@@ -197,10 +200,12 @@ public class TeamNotificationHelper {
} else if (field.getKey() == TeamFieldEnum.AllMute) {
TeamAllMuteModeEnum teamAllMuteModeEnum = (TeamAllMuteModeEnum) field.getValue();
if (teamAllMuteModeEnum == TeamAllMuteModeEnum.Cancel) {
sb.append("取消群全员禁言");
sb.append("群聊已开启");
} else {
sb.append("群全员禁言");
sb.append("群聊已结束,如有问题请联系个案管理师");
}
//发送通知告知群聊界面全员禁言或者取消全员禁言
EventBus.getDefault().post(new ChatGroupStatusEvent());
} else {
sb.append("群" + field.getKey() + "被更新为 " + field.getValue());
}
......
......@@ -57,7 +57,6 @@ import com.yidianling.nimbase.common.util.string.StringUtil;
import com.yidianling.uikit.api.NimUIKit;
import com.yidianling.uikit.api.NimUIKitImpl;
import com.yidianling.uikit.business.ait.AitTextChangeListener;
import com.yidianling.uikit.custom.bridge.ActionHandlerStorage;
import com.yidianling.uikit.custom.widget.SafeHelpRemindDialog;
import java.io.File;
......@@ -104,7 +103,7 @@ public class InputPanel implements IEmoticonSelectedListener, IAudioRecordCallba
protected View sendMessageButtonInInputBar;
/***发送消息按钮*/
protected View emojiButtonInInputBar;
protected View messageInputBar;
public View messageInputBar;
protected View messageEditLL;
protected FrameLayout audioTextSwitchLayout;
......@@ -407,10 +406,10 @@ public class InputPanel implements IEmoticonSelectedListener, IAudioRecordCallba
//验证用户是否已经绑定手机,若没有绑定则弹出提示
// 账户信息是null时 判断是否是聊天室 不是聊天室提示用户退出重试
if (ActionHandlerStorage.getL(container.account) == null && container.sessionType != SessionTypeEnum.ChatRoom) {
ToastUtil.toastShort("请退出聊天界面重试");
return;
}
// if (ActionHandlerStorage.getL(container.account) == null && container.sessionType != SessionTypeEnum.ChatRoom) {
// ToastUtil.toastShort("请退出聊天界面重试");
// return;
// }
if (v == switchToTextButtonInInputBar) {
switchToTextLayout(true);// 显示文本发送的布局
......@@ -657,7 +656,7 @@ public class InputPanel implements IEmoticonSelectedListener, IAudioRecordCallba
/**
* 隐藏键盘布局
*/
private void hideInputMethod() {
public void hideInputMethod() {
isKeyboardShowed = false;
uiHandler.removeCallbacks(showTextRunnable);
InputMethodManager imm = (InputMethodManager) container.activity.getSystemService(Context.INPUT_METHOD_SERVICE);
......
......@@ -2,6 +2,8 @@ package com.yidianling.uikit.business.session.viewholder;
import android.text.method.LinkMovementMethod;
import android.text.style.ImageSpan;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.yidianling.im.R;
......@@ -16,6 +18,7 @@ public class MsgViewHolderNotification extends MsgViewHolderBase {
}
protected TextView notificationTextView;
protected ImageView ivLabel;
@Override
protected int getContentResId() {
......@@ -25,6 +28,8 @@ public class MsgViewHolderNotification extends MsgViewHolderBase {
@Override
protected void inflateContentView() {
notificationTextView = (TextView) view.findViewById(R.id.message_item_notification_label);
ivLabel = view.findViewById(R.id.iv_label);
}
@Override
......@@ -39,6 +44,12 @@ public class MsgViewHolderNotification extends MsgViewHolderBase {
private void handleTextNotification(String text) {
MoonUtil.identifyFaceExpressionAndATags(context, notificationTextView, text, ImageSpan.ALIGN_BOTTOM);
notificationTextView.setMovementMethod(LinkMovementMethod.getInstance());
if (getDisplayText().contains("群聊已结束")){
ivLabel.setVisibility(View.VISIBLE);
}else {
ivLabel.setVisibility(View.GONE);
}
}
@Override
......
package com.yidianling.uikit.business.team.helper;
import android.content.Context;
import android.os.Handler;
import android.util.Log;
import com.netease.nimlib.sdk.NIMClient;
import com.netease.nimlib.sdk.RequestCallback;
import com.netease.nimlib.sdk.ResponseCode;
import com.netease.nimlib.sdk.msg.MessageBuilder;
import com.netease.nimlib.sdk.msg.MsgService;
import com.netease.nimlib.sdk.msg.constant.MsgStatusEnum;
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
import com.netease.nimlib.sdk.msg.model.CustomMessageConfig;
import com.netease.nimlib.sdk.msg.model.IMMessage;
import com.netease.nimlib.sdk.team.TeamService;
import com.netease.nimlib.sdk.team.constant.TeamBeInviteModeEnum;
import com.netease.nimlib.sdk.team.constant.TeamFieldEnum;
import com.netease.nimlib.sdk.team.constant.TeamTypeEnum;
import com.netease.nimlib.sdk.team.model.CreateTeamResult;
import com.netease.nimlib.sdk.team.model.Team;
import com.yidianling.common.tools.LogUtil;
import com.yidianling.common.tools.ToastUtil;
import com.yidianling.im.R;
import com.yidianling.im.session.SessionHelper;
import com.yidianling.nimbase.common.ToastHelper;
import com.yidianling.nimbase.common.ui.dialog.DialogMaker;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by hzxuwen on 2015/9/25.
*/
public class TeamCreateHelper {
private static final String TAG = TeamCreateHelper.class.getSimpleName();
private static final int DEFAULT_TEAM_CAPACITY = 200;
/**
* 创建讨论组
*/
public static void createNormalTeam(final Context context, List<String> memberAccounts, final boolean isNeedBack, final RequestCallback<CreateTeamResult> callback) {
String teamName = "讨论组";
DialogMaker.showProgressDialog(context, context.getString(R.string.empty), true);
// 创建群
HashMap<TeamFieldEnum, Serializable> fields = new HashMap<TeamFieldEnum, Serializable>();
fields.put(TeamFieldEnum.Name, teamName);
NIMClient.getService(TeamService.class).createTeam(fields, TeamTypeEnum.Normal, "",
memberAccounts).setCallback(
new RequestCallback<CreateTeamResult>() {
@Override
public void onSuccess(CreateTeamResult result) {
DialogMaker.dismissProgressDialog();
ArrayList<String> failedAccounts = result.getFailedInviteAccounts();
if (failedAccounts != null && !failedAccounts.isEmpty()) {
TeamHelper.onMemberTeamNumOverrun(failedAccounts, context);
} else {
ToastUtil.toastShort("创建群聊成功");
}
if (isNeedBack) {
// SessionHelper.startTeamSession(context, result.getTeam().getId(), MainActivity.class, null); // 进入创建的群
LogUtil.e("进入创建的群:"+result.getTeam().getId());
} else {
SessionHelper.startTeamSession(context, result.getTeam().getId());
}
if (callback != null) {
callback.onSuccess(result);
}
}
@Override
public void onFailed(int code) {
DialogMaker.dismissProgressDialog();
if (code == ResponseCode.RES_TEAM_ECOUNT_LIMIT) {
ToastUtil.toastShort("已达到人数限制");
} else {
ToastUtil.toastShort("创建群聊失败:code="+code);
}
Log.e(TAG, "create team error: " + code);
}
@Override
public void onException(Throwable exception) {
DialogMaker.dismissProgressDialog();
}
}
);
}
/**
* 创建高级群
*/
public static void createAdvancedTeam(final Context context, List<String> memberAccounts) {
String teamName = "高级群";
ToastUtil.toastShort("创建中。。。。");
// 创建群
TeamTypeEnum type = TeamTypeEnum.Advanced;
HashMap<TeamFieldEnum, Serializable> fields = new HashMap<>();
fields.put(TeamFieldEnum.Name, teamName);
fields.put(TeamFieldEnum.BeInviteMode, TeamBeInviteModeEnum.NoAuth);
NIMClient.getService(TeamService.class).createTeam(fields, type, "",
memberAccounts).setCallback(
new RequestCallback<CreateTeamResult>() {
@Override
public void onSuccess(CreateTeamResult result) {
Log.i(TAG, "create team success, team id =" + result.getTeam().getId() + ", now begin to update property...");
onCreateSuccess(context, result);
}
@Override
public void onFailed(int code) {
DialogMaker.dismissProgressDialog();
String tip;
if (code == ResponseCode.RES_TEAM_ECOUNT_LIMIT) {
tip = "邀请失败成员人数上限为200人";
} else if (code == ResponseCode.RES_TEAM_LIMIT) {
tip = "创建失败,创建群数量达到限制";
} else {
tip = "创建失败code:"+code;
}
ToastHelper.showToast(context, tip);
Log.e(TAG, "create team error: " + code);
}
@Override
public void onException(Throwable exception) {
DialogMaker.dismissProgressDialog();
}
}
);
}
/**
* 群创建成功回调
*/
private static void onCreateSuccess(final Context context, CreateTeamResult result) {
if (result == null) {
Log.e(TAG, "onCreateSuccess exception: team is null");
return;
}
final Team team = result.getTeam();
if (team == null) {
Log.e(TAG, "onCreateSuccess exception: team is null");
return;
}
Log.i(TAG, "create and update team success");
DialogMaker.dismissProgressDialog();
// 检查有没有邀请失败的成员
ArrayList<String> failedAccounts = result.getFailedInviteAccounts();
if (failedAccounts != null && !failedAccounts.isEmpty()) {
TeamHelper.onMemberTeamNumOverrun(failedAccounts, context);
} else {
ToastUtil.toastShort("创建高级群成功");
}
// 演示:向群里插入一条Tip消息,使得该群能立即出现在最近联系人列表(会话列表)中,满足部分开发者需求
Map<String, Object> content = new HashMap<>(1);
content.put("content", "成功创建高级群");
IMMessage msg = MessageBuilder.createTipMessage(team.getId(), SessionTypeEnum.Team);
msg.setRemoteExtension(content);
CustomMessageConfig config = new CustomMessageConfig();
config.enableUnreadCount = false;
msg.setConfig(config);
msg.setStatus(MsgStatusEnum.success);
NIMClient.getService(MsgService.class).saveMessageToLocal(msg, true);
// 发送后,稍作延时后跳转
new Handler(context.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
SessionHelper.startTeamSession(context, team.getId()); // 进入创建的群
}
}, 50);
}
}
......@@ -112,19 +112,42 @@
android:textColor="#999999"
android:textSize="11dp" />
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
android:layout_marginTop="5dp"
>
<TextView
android:id="@+id/chat_message_content"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/not_disturb"
android:layout_marginEnd="@dimen/platform_dp_10"
android:layout_marginBottom="18dp"
android:layout_marginRight="35dp"
android:layout_marginTop="5dp"
android:ellipsize="end"
android:includeFontPadding="false"
android:layout_toLeftOf="@id/not_disturb"
android:maxLines="1"
android:text="你好,请问你遇到了什么烦恼?我可你好,请问你遇到了什么烦恼?我可以帮…"
android:textColor="#999999"
android:textSize="14dp" />
<ImageView
android:layout_width="@dimen/platform_dp_15"
android:layout_height="@dimen/platform_dp_15"
android:src="@drawable/team_not_disturb"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/chat_message_content"
app:layout_constraintBottom_toBottomOf="@id/chat_message_content"
android:id="@+id/not_disturb"
android:visibility="gone"
>
</ImageView>
</androidx.constraintlayout.widget.ConstraintLayout>
<View
android:layout_width="match_parent"
......
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="@+id/message_item_notification_label"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="7dip"
android:layout_marginRight="7dip"
android:orientation="horizontal"
android:background="@drawable/im_nim_bg_message_tip"
android:gravity="center"
android:paddingLeft="7dip"
android:paddingRight="7dip"
>
<ImageView
android:id="@+id/iv_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:src="@drawable/ic_group_chat_end"
/>
<TextView
android:id="@+id/message_item_notification_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="7dp"
android:layout_marginRight="7dp"
android:includeFontPadding="false"
android:textColor="#ffffff"
android:textSize="12sp"/>
</LinearLayout>
</merge>
\ No newline at end of file
......@@ -51,12 +51,12 @@
android:layout_gravity="center_horizontal"
android:layout_weight="2"
android:ellipsize="end"
android:singleLine="true"
android:gravity="center"
android:maxEms="12"
android:maxLength="12"
android:maxEms="11"
android:textColor="@color/im_color_242424"
android:textSize="17dp"
tools:text="现现现现现现在在现在在在在现在在" />
tools:text="我是第几个字体马上查看一下" />
<TextView
android:id="@+id/tv_bottom_title"
......
......@@ -607,7 +607,6 @@
android:layout_marginEnd="@dimen/platform_dp_12"
android:layout_marginBottom="@dimen/platform_dp_8"
>
</TextView>
<FrameLayout
android:id="@+id/fl_question_content"
......@@ -615,9 +614,6 @@
android:layout_height="wrap_content"
android:background="@color/white"
android:visibility="gone" />
<include
layout="@layout/im_nim_message_activity_bottom_layout" />
</LinearLayout>
......@@ -88,6 +88,7 @@ dependencies {
api project(':ydl-webview')
api project(':ydl-platform')
api project(":ydl-pay")
// implementation project(":ydl-tuicore")
implementation modularPublication('com.ydl:m-user-api')
implementation modularPublication('com.ydl:m-course-api')
implementation modularPublication('com.ydl:m-im-api')
......@@ -107,5 +108,6 @@ dependencies {
api(rootProject.ext.dependencies["ydl-platform"]) {
transitive = true
}
// implementation rootProject.ext.dependencies["ydl-tuicore"]
}
}
......@@ -325,6 +325,7 @@ public class AccountSettingActivity extends BaseActivity implements View.OnClick
return;
}
userHttp.bindQQ(new BindQQ(map.get("openid"), map.get("unionid")))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(o -> {
dismissProgressDialog();
......
......@@ -4,5 +4,4 @@ include ':app',
':m-home',
':m-consultant', ':m-muse', ':m-fm', ':m-tests', ":m-course",
":m-im",":m-dynamic","m-article","m-audioim","m-user","m-confide"
include ':ydl-tuicore'
......@@ -52,14 +52,14 @@ public class DefaultFormatPrinter {
public void printJsonRequest(@NonNull Request request, @NonNull String bodyString) {
final String requestBody = LINE_SEPARATOR + BODY_TAG + LINE_SEPARATOR + bodyString;
final String tag = getTag(true);
if (!request.url().toString().contains("writeMaiDianData")){
NetLogUtils.debugInfo(tag, REQUEST_UP_LINE);
logLines(tag, new String[]{URL_TAG + request.url()}, false);
logLines(tag, getRequest(request), true);
logLines(tag, requestBody.split(LINE_SEPARATOR), true);
if (!request.url().toString().contains("writemaidiandata")){
NetLogUtils.debugInfo(tag, END_LINE);
}
}
/**
......@@ -70,7 +70,7 @@ public class DefaultFormatPrinter {
public void printFileRequest(@NonNull Request request) {
final String tag = getTag(true);
if (!request.url().toString().contains("writeMaiDianData")){
NetLogUtils.debugInfo(tag, REQUEST_UP_LINE);
logLines(tag, new String[]{URL_TAG + request.url()}, false);
logLines(tag, getRequest(request), true);
......@@ -78,6 +78,8 @@ public class DefaultFormatPrinter {
NetLogUtils.debugInfo(tag, END_LINE);
}
}
/**
* 打印网络响应信息, 当网络响应时 {{@link okhttp3.ResponseBody}} 可以解析的情况
*
......@@ -100,13 +102,14 @@ public class DefaultFormatPrinter {
final String responseBody = LINE_SEPARATOR + BODY_TAG + LINE_SEPARATOR + bodyString;
final String tag = getTag(false);
final String[] urlLine = {URL_TAG + responseUrl, N};
if (!responseUrl.contains("writeMaiDianData")){
NetLogUtils.debugInfo(tag, RESPONSE_UP_LINE);
logLines(tag, urlLine, true);
logLines(tag, getResponse(headers, chainMs, code, isSuccessful, segments, message), true);
logLines(tag, responseBody.split(LINE_SEPARATOR), true);
NetLogUtils.debugInfo(tag, END_LINE);
}
}
/**
* 打印网络响应信息, 当网络响应时 {{@link okhttp3.ResponseBody}} 为 {@code null} 或不可解析的情况
......@@ -124,13 +127,14 @@ public class DefaultFormatPrinter {
@NonNull List<String> segments, @NonNull String message, @NonNull final String responseUrl) {
final String tag = getTag(false);
final String[] urlLine = {URL_TAG + responseUrl, N};
if (!responseUrl.contains("writeMaiDianData")){
NetLogUtils.debugInfo(tag, RESPONSE_UP_LINE);
logLines(tag, urlLine, true);
logLines(tag, getResponse(headers, chainMs, code, isSuccessful, segments, message), true);
logLines(tag, OMITTED_RESPONSE, true);
NetLogUtils.debugInfo(tag, END_LINE);
}
}
/**
* 对 {@code lines} 中的信息进行逐行打印
......
......@@ -88,6 +88,7 @@ dependencies {
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib'
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk7'
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-common'
exclude group: 'com.ydl', module: 'pictureselector'
}
api rootProject.ext.dependencies["ydl-utils"]
......
......@@ -190,7 +190,7 @@ class HttpConfig {
return Interceptor {
val request: Request = it.request()
val originalResponse: Response = it.proceed(request)
// if (!appDebug){
if (!appDebug){
val code = originalResponse.code()
// 接口返回错误的情况下,埋点告诉服务器原因
if (code != 200) {
......@@ -222,7 +222,7 @@ class HttpConfig {
AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.API, "writeMaiDianDatacode$code:$api---params:$params ---- message:$message")
}
}
// }
}
originalResponse
}
}
......
......@@ -157,6 +157,9 @@ class LogHelper private constructor() {
val agoraRtmLog = getAgoraRTMLog(BaseApp.getApp())
val agoraRtmBackLog = getAgoraRtmBackLog(BaseApp.getApp())
// 腾讯im日志
val tencentLog = getTencentLog(BaseApp.getApp())
if (zipFile.exists()) zipFile.delete()
zipFile.createNewFile()
......@@ -176,6 +179,10 @@ class LogHelper private constructor() {
files.add(agoraRtmBackLog)
}
if (tencentLog.exists()){
files.add(tencentLog)
}
// ZipUtils.toZip(getLogFolder().absolutePath, FileOutputStream(zipFile), true)
ZipUtils.toZip(files, FileOutputStream(zipFile))
return zipFile
......@@ -254,6 +261,12 @@ class LogHelper private constructor() {
return File(agoraRTMLog)
}
// 获取腾讯im日志
private fun getTencentLog(context: Context):File{
val agoraRTMLog = FileUtils.getSDDirectory() + "/Android/data/" + context.packageName + "/files/log/tencent/imsdk"
return File(agoraRTMLog)
}
private object Holder {
val INSTANCE = LogHelper()
......
......@@ -15,6 +15,8 @@ import com.ydl.ydlcommon.adapter.DialogListAdapter;
import com.ydl.ydlcommon.view.FullyLinearLayoutManager;
import com.ydl.ydlcommon.R;
import org.w3c.dom.Text;
import java.util.List;
//import com.yidianling.common.view.FullyLinearLayoutManager;
......@@ -42,6 +44,8 @@ public class ListDialog extends Dialog {
private View contentView; //对话框中间加载的其他布局界面
private DialogListAdapter adapter;
private String last_str; //最后一个按钮
private String titleStr; //标题内容
private OnClickListener Last_btnClickListener;
private int itemTextColor;
......@@ -53,12 +57,17 @@ public class ListDialog extends Dialog {
private ListDialog.Builder.OnItemClickLister mOnItemClickLister;
public Builder(Context context, List<String> mDatas, int itemTextColor,String titleStr) {
this.context = context;
this.mDatas = mDatas;
this.itemTextColor = itemTextColor;
this.titleStr=titleStr;
}
public Builder(Context context, List<String> mDatas, int itemTextColor) {
this.context = context;
this.mDatas = mDatas;
this.itemTextColor = itemTextColor;
}
/**
* 设置对话框界面
*
......@@ -80,7 +89,6 @@ public class ListDialog extends Dialog {
return this;
}
public ListDialog.Builder SetLastStr(String bottom) {
this.last_str = bottom;
return this;
......@@ -129,7 +137,18 @@ public class ListDialog extends Dialog {
layout.findViewById(R.id.last_btn).setVisibility(
View.GONE);
}
if (titleStr!=null){
layout.findViewById(R.id.titleLine).setVisibility(
View.VISIBLE);
layout.findViewById(R.id.title).setVisibility(
View.VISIBLE);
((TextView)layout.findViewById(R.id.title)).setText(titleStr);
}else{
layout.findViewById(R.id.titleLine).setVisibility(
View.GONE);
layout.findViewById(R.id.title).setVisibility(
View.GONE);
}
if (mDatas != null && mDatas.size() > 0) {
RecyclerView dialog_list_rcv = (RecyclerView) layout.findViewById(R.id.dialog_list_rcv);
if (adapter == null) {
......
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center"
>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:minWidth="200dp"
android:background="@drawable/dialog_list_bg"
android:orientation="vertical"
android:scrollbars="vertical">
<androidx.recyclerview.widget.RecyclerView
android:layout_marginTop="5dp"
android:id="@+id/dialog_list_rcv"
android:layout_width="match_parent"
android:layout_height="match_parent"></androidx.recyclerview.widget.RecyclerView>
<TextView
android:id="@+id/last_btn"
android:layout_width="match_parent"
android:layout_height="40dp"
android:textSize="18sp"
android:gravity="center"
android:layout_marginBottom="5dp"
android:background="@drawable/normaldialog_right_btn_select"
android:text="确定"/>
</LinearLayout>
</LinearLayout>
</ScrollView>
\ No newline at end of file
plugins {
id 'com.android.library'
}
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply from: 'publish.gradle'
android {
compileSdkVersion rootProject.ext.android["compileSdkVersion"]
buildToolsVersion rootProject.ext.android["buildToolsVersion"]
defaultConfig {
minSdkVersion rootProject.ext.android["minSdkVersion"]
targetSdkVersion rootProject.ext.android["targetSdkVersion"]
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
api fileTree(include: ['*.jar','*.aar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation(rootProject.ext.dependencies["support-multidex"])
implementation(rootProject.ext.dependencies["recyclerview-v7"])
implementation(rootProject.ext.dependencies["appcompat-v7"])
implementation(rootProject.ext.dependencies["design"])
implementation(rootProject.ext.dependencies["constraint-layout"])
implementation(rootProject.ext.dependencies["appcompat-v7"])
implementation(rootProject.ext.dependencies["constraint-layout"])
implementation(rootProject.ext.dependencies["okhttp3-logging"])
implementation(rootProject.ext.dependencies["retrofit-converter-gson"])
implementation(rootProject.ext.dependencies["retrofit"])
implementation(rootProject.ext.dependencies["okhttp3"])
implementation(rootProject.ext.dependencies["glide"])
implementation(rootProject.ext.dependencies["gson"])
implementation(rootProject.ext.dependencies["eventbus"])
implementation "com.blankj:utilcode:1.25.9"
api "com.tencent.liteav:LiteAVSDK_TRTC:latest.release"
api "com.tencent.imsdk:imsdk-plus:latest.release"
}
\ No newline at end of file
apply plugin: 'maven'
def mavenRepositoryUrl = "http://nexus.yidianling.com/repository/AndroidReleases/"
def getVersionName() {
return hasProperty('VERSION_NAME') ? VERSION_NAME : rootProject.ext.ydlPublishVersion[project.getName()]
}
uploadArchives {
configuration = configurations.archives
repositories.mavenDeployer {
repository(url: mavenRepositoryUrl) {
authentication(userName: "admin", password: "fjoi#1+#@")
}
pom.project {
artifactId project.getName().replace('_', "-")
groupId "com.ydl"
version getVersionName()
packaging 'aar' //填写aar
}
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tencent.qcloud.tuicore">
<application>
<provider
android:name=".util.TUIFileProvider"
android:authorities="${applicationId}.tuicore.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths_public"/>
</provider>
<!--通话界面-->
<activity
android:name=".calling.videocall.VideoCallingActivity"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:theme="@style/VideoCallActivityTheme"
/>
<!--接听界面-->
<activity
android:name=".calling.videocall.YDLInvitionActivity"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:theme="@style/VideoCallActivityTheme"
/>
</application>
</manifest>
\ No newline at end of file
package com.tencent.qcloud.tuicore;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import com.tencent.qcloud.tuicore.interfaces.ITUINotification;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* 负责通知注册、移除和触发
*/
class EventManager {
private static final String TAG = ServiceManager.class.getSimpleName();
private static class EventManagerHolder {
private static final EventManager eventManager = new EventManager();
}
public static EventManager getInstance() {
return EventManagerHolder.eventManager;
}
private final Map<Pair<String, String>, List<ITUINotification>> eventMap = new ConcurrentHashMap<>();
private EventManager() {}
public void registerEvent(String key, String subKey, ITUINotification notification) {
Log.i(TAG, "registerEvent : key : " + key + ", subKey : " + subKey + ", notification : " + notification);
if (TextUtils.isEmpty(key) || TextUtils.isEmpty(subKey) || notification == null) {
return;
}
Pair<String, String> keyPair = new Pair<>(key, subKey);
List<ITUINotification> list = eventMap.get(keyPair);
if (list == null) {
list = new CopyOnWriteArrayList<>();
eventMap.put(keyPair, list);
}
if (!list.contains(notification)) {
list.add(notification);
}
}
public void unRegisterEvent(String key, String subKey, ITUINotification notification) {
Log.i(TAG, "removeEvent : key : " + key + ", subKey : " + subKey + " notification : " + notification);
if (TextUtils.isEmpty(key) || TextUtils.isEmpty(subKey) || notification == null) {
return;
}
Pair<String, String> keyPair = new Pair<>(key, subKey);
List<ITUINotification> list = eventMap.get(keyPair);
if (list == null) {
return;
}
list.remove(notification);
}
public void unRegisterEvent(ITUINotification notification) {
Log.i(TAG, "removeEvent : notification : " + notification);
if (notification == null) {
return;
}
for (Pair<String, String> key : eventMap.keySet()) {
List<ITUINotification> value = eventMap.get(key);
if (value == null) {
continue;
}
Iterator<ITUINotification> notificationIterator = value.iterator();
while (notificationIterator.hasNext()) {
ITUINotification item = notificationIterator.next();
if (item == notification) {
notificationIterator.remove();
}
}
}
}
public void notifyEvent(String key, String subKey, Map<String, Object> param) {
Log.i(TAG, "notifyEvent : key : " + key + ", subKey : " + subKey);
if (TextUtils.isEmpty(key) || TextUtils.isEmpty(subKey)) {
return;
}
Pair<String, String> keyPair = new Pair<>(key, subKey);
List<ITUINotification> notificationList = eventMap.get(keyPair);
if (notificationList != null) {
for(ITUINotification notification : notificationList) {
notification.onNotifyEvent(key, subKey, param);
}
}
}
}
package com.tencent.qcloud.tuicore;
import android.text.TextUtils;
import android.util.Log;
import com.tencent.qcloud.tuicore.interfaces.ITUIExtension;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* 页面扩展注册和获取
*/
class ExtensionManager {
private static final String TAG = ExtensionManager.class.getSimpleName();
private static class ExtensionManagerHolder {
private static final ExtensionManager extensionManager = new ExtensionManager();
}
public static ExtensionManager getInstance() {
return ExtensionManagerHolder.extensionManager;
}
private final Map<String, List<ITUIExtension>> extensionHashMap = new ConcurrentHashMap<>();
private ExtensionManager() {}
public void registerExtension(String key, ITUIExtension extension) {
Log.i(TAG, "registerExtension key : " + key + ", extension : " + extension);
if (TextUtils.isEmpty(key) || extension == null) {
return;
}
List<ITUIExtension> list = extensionHashMap.get(key);
if (list == null) {
list = new CopyOnWriteArrayList<>();
extensionHashMap.put(key, list);
}
if (!list.contains(extension)) {
list.add(extension);
}
}
public void unRegisterExtension(String key, ITUIExtension extension) {
Log.i(TAG, "removeExtension key : " + key + ", extension : " + extension);
if (TextUtils.isEmpty(key) || extension == null) {
return;
}
List<ITUIExtension> list = extensionHashMap.get(key);
if (list == null) {
return;
}
list.remove(extension);
}
public Map<String, Object> getExtensionInfo(String key, Map<String, Object> param) {
Log.i(TAG, "getExtensionInfo key : " + key );
if (TextUtils.isEmpty(key)) {
return null;
}
List<ITUIExtension> list = extensionHashMap.get(key);
if (list == null) {
return null;
}
for(ITUIExtension extension : list) {
return extension.onGetExtensionInfo(key, param);
}
return null;
}
}
package com.tencent.qcloud.tuicore;
import android.text.TextUtils;
import android.util.Log;
import com.tencent.qcloud.tuicore.interfaces.ITUIService;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Service 注册和调用
*/
class ServiceManager {
private static final String TAG = ServiceManager.class.getSimpleName();
private static class ServiceManagerHolder {
private static final ServiceManager serviceManager = new ServiceManager();
}
public static ServiceManager getInstance() {
return ServiceManagerHolder.serviceManager;
}
private final Map<String, ITUIService> serviceMap = new ConcurrentHashMap<>();
private ServiceManager() {}
public void registerService(String serviceName, ITUIService service) {
Log.i(TAG, "registerService : " + serviceName + " " + service);
if (TextUtils.isEmpty(serviceName) || service == null) {
return;
}
serviceMap.put(serviceName, service);
}
public Object callService(String serviceName, String method, Map<String, Object> param) {
Log.i(TAG, "callService : " + serviceName + " method : " + method);
ITUIService service = serviceMap.get(serviceName);
if (service != null) {
return service.onCall(method, param);
} else {
Log.w(TAG, "can't find service : " + serviceName);
return null;
}
}
}
package com.tencent.qcloud.tuicore;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import com.tencent.imsdk.v2.V2TIMUserFullInfo;
import org.json.JSONObject;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* 公共配置,如文件路径配置、用户信息
*/
public class TUIConfig {
private static Context appContext;
private static String appDir = "";
private static String selfFaceUrl = "";
private static String selfNickName = "";
private static int selfAllowType = 0;
private static long selfBirthDay = 0L;
private static String selfSignature = "";
private static int gender;
private static final String RECORD_DIR_SUFFIX = "/record/";
private static final String RECORD_DOWNLOAD_DIR_SUFFIX = "/record/download/";
private static final String VIDEO_DOWNLOAD_DIR_SUFFIX = "/video/download/";
private static final String IMAGE_BASE_DIR_SUFFIX = "/image/";
private static final String IMAGE_DOWNLOAD_DIR_SUFFIX = "/image/download/";
private static final String MEDIA_DIR_SUFFIX = "/media/";
private static final String FILE_DOWNLOAD_DIR_SUFFIX = "/file/download/";
private static final String CRASH_LOG_DIR_SUFFIX = "/crash/";
public static void init(Context context) {
TUIConfig.appContext = context;
initPath();
}
public static String getDefaultAppDir() {
if (TextUtils.isEmpty(appDir)) {
Context context = null;
if (appContext != null) {
context = appContext;
} else if (TUIRouter.getContext() != null) {
context = TUIRouter.getContext();
} else if (TUILogin.getAppContext() != null) {
context = TUILogin.getAppContext();
}
if (context != null) {
appDir = context.getFilesDir().getAbsolutePath();
}
}
return appDir;
}
public static void setDefaultAppDir(String appDir) {
TUIConfig.appDir = appDir;
}
public static String getRecordDir() {
return getDefaultAppDir() + RECORD_DIR_SUFFIX;
}
public static String getRecordDownloadDir() {
return getDefaultAppDir() + RECORD_DOWNLOAD_DIR_SUFFIX;
}
public static String getVideoDownloadDir() {
return getDefaultAppDir() + VIDEO_DOWNLOAD_DIR_SUFFIX;
}
public static String getImageBaseDir() {
return getDefaultAppDir() + IMAGE_BASE_DIR_SUFFIX;
}
public static String getImageDownloadDir() {
return getDefaultAppDir() + IMAGE_DOWNLOAD_DIR_SUFFIX;
}
public static String getMediaDir() {
return getDefaultAppDir() + MEDIA_DIR_SUFFIX;
}
public static String getFileDownloadDir() {
return getDefaultAppDir() + FILE_DOWNLOAD_DIR_SUFFIX;
}
public static String getCrashLogDir() {
return getDefaultAppDir() + CRASH_LOG_DIR_SUFFIX;
}
public static String getSelfFaceUrl() {
return selfFaceUrl;
}
public static void setSelfFaceUrl(String selfFaceUrl) {
TUIConfig.selfFaceUrl = selfFaceUrl;
}
public static String getSelfNickName() {
return selfNickName;
}
public static void setSelfNickName(String selfNickName) {
TUIConfig.selfNickName = selfNickName;
}
public static int getSelfAllowType() {
return selfAllowType;
}
public static void setSelfAllowType(int selfAllowType) {
TUIConfig.selfAllowType = selfAllowType;
}
public static long getSelfBirthDay() {
return selfBirthDay;
}
public static void setSelfBirthDay(long selfBirthDay) {
TUIConfig.selfBirthDay = selfBirthDay;
}
public static String getSelfSignature() {
return selfSignature;
}
public static void setSelfSignature(String selfSignature) {
TUIConfig.selfSignature = selfSignature;
}
public static void setGender(int gender) {
TUIConfig.gender = gender;
}
public static int getGender() {
return gender;
}
/**
* 设置登录用户信息
*/
public static void setSelfInfo(V2TIMUserFullInfo userFullInfo) {
TUIConfig.selfFaceUrl = userFullInfo.getFaceUrl();
TUIConfig.selfNickName = userFullInfo.getNickName();
TUIConfig.selfAllowType = userFullInfo.getAllowType();
TUIConfig.selfBirthDay = userFullInfo.getBirthday();
TUIConfig.selfSignature = userFullInfo.getSelfSignature();
TUIConfig.gender = userFullInfo.getGender();
}
/**
* 清除登录用户信息
*/
public static void clearSelfInfo() {
TUIConfig.selfFaceUrl = "";
TUIConfig.selfNickName = "";
TUIConfig.selfAllowType = 0;
TUIConfig.selfBirthDay = 0L;
TUIConfig.selfSignature = "";
}
/**
* 初始化文件目录
*/
public static void initPath() {
File f = new File(getMediaDir());
if (!f.exists()) {
f.mkdirs();
}
f = new File(getRecordDir());
if (!f.exists()) {
f.mkdirs();
}
f = new File(getRecordDownloadDir());
if (!f.exists()) {
f.mkdirs();
}
f = new File(getVideoDownloadDir());
if (!f.exists()) {
f.mkdirs();
}
f = new File(getImageDownloadDir());
if (!f.exists()) {
f.mkdirs();
}
f = new File(getFileDownloadDir());
if (!f.exists()) {
f.mkdirs();
}
f = new File(getCrashLogDir());
if (!f.exists()) {
f.mkdirs();
}
}
public static Context getAppContext() {
return appContext;
}
public static void setSceneOptimizParams(final String scene){
new Thread(new Runnable() {
@Override
public void run() {
try {
String packageName = "";
String sdkAPPId = TUILogin.getSdkAppId() + "";
String userId = TUILogin.getUserId();
if(getAppContext() != null){
packageName = getAppContext().getPackageName();
}
URL url = new URL("https://demos.trtc.tencent-cloud.com/prod/base/v1/events/stat");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
JSONObject msgObject = new JSONObject();
msgObject.put("sdkappid", sdkAPPId);
msgObject.put("bundleId", "");
msgObject.put("component", scene);
msgObject.put("package", packageName);
JSONObject bodyObject = new JSONObject();
bodyObject.put("userId", userId);
bodyObject.put("event", "useScenario");
bodyObject.put("msg", msgObject);
String paramStr = String.valueOf(bodyObject);
OutputStream out = conn.getOutputStream();
out.write(paramStr.getBytes());
out.flush();
out.close();
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
InputStream is = conn.getInputStream();
ByteArrayOutputStream message = new ByteArrayOutputStream();
int len = 0;
byte buffer[] = new byte[1024];
while ((len = is.read(buffer)) != -1) {
message.write(buffer, 0, len);
}
String msg = new String(message.toByteArray());
Log.d("setSceneOptimizParams", "msg:" + msg);
is.close();
message.close();
conn.disconnect();
} else {
Log.d("setSceneOptimizParams", "ResponseCode:" + conn.getResponseCode());
}
} catch (Exception e) {
Log.d("TUICore", "setSceneOptimizParams exception");
}
}
}).start();
}
}
package com.tencent.qcloud.tuicore;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.tencent.qcloud.tuicore.interfaces.ITUIExtension;
import com.tencent.qcloud.tuicore.interfaces.ITUINotification;
import com.tencent.qcloud.tuicore.interfaces.ITUIService;
import java.util.Map;
/**
* TUI 插件核心类,主要负责 TUI 插件间数据的传递,通知的广播,功能的扩展等
*/
public class TUICore {
private static final String TAG = TUICore.class.getSimpleName();
/**
* 注册 Service 服务
* @param serviceName 服务名
* @param service service 服务对象
*/
public static void registerService(String serviceName, ITUIService service) {
ServiceManager.getInstance().registerService(serviceName, service);
}
/**
* 唤起 Service 服务
*
* @param serviceName 服务名
* @param method 方法名
* @param param 透传给服务方的数据
* @return 返回对象
*/
public static Object callService(String serviceName, String method, Map<String, Object> param) {
return ServiceManager.getInstance().callService(serviceName, method, param);
}
/**
* 启动 Activity
* @param activityName Activity 名,例如 "TUIGroupChatActivity"
* @param param 传给 Activity 的参数
*/
public static void startActivity(String activityName, Bundle param) {
startActivity(null, activityName, param, -1);
}
/**
* 启动 Activity
* @param starter 启动者,可以是 {@link Context},也可以是 {@link Fragment}
* @param activityName Activity 名,例如 "TUIGroupChatActivity"
* @param param 传给 Activity 的参数
*/
public static void startActivity(@Nullable Object starter, String activityName, Bundle param) {
startActivity(starter, activityName, param, -1);
}
/**
* 启动 Activity
* @param starter 启动者,可以是 {@link Context},也可以是 {@link Fragment}
* @param activityName Activity 名,例如 "TUIGroupChatActivity"
* @param param 传给 Activity 的参数
* @param requestCode 传给 Activity 的请求值,用来在 Activity 结束时在启动者的 onActivityResult 方法中返回结果,大于等于 0 有效。
*/
public static void startActivity(@Nullable Object starter, String activityName, Bundle param, int requestCode) {
TUIRouter.Navigation navigation = TUIRouter.getInstance().setDestination(activityName).putExtras(param);
if (starter instanceof Fragment) {
navigation.navigate((Fragment) starter, requestCode);
} else if (starter instanceof Context) {
navigation.navigate((Context) starter, requestCode);
} else {
navigation.navigate((Context) null, requestCode);
}
}
/**
* 注册通知
*/
public static void registerEvent(String key, String subKey, ITUINotification notification) {
EventManager.getInstance().registerEvent(key, subKey, notification);
}
/**
* 移除指定 Key 和 subKey 的所有通知
*/
public static void unRegisterEvent(String key, String subKey, ITUINotification notification) {
EventManager.getInstance().unRegisterEvent(key, subKey, notification);
}
/**
* 移除指定通知对象的所有通知
*/
public static void unRegisterEvent(ITUINotification notification) {
EventManager.getInstance().unRegisterEvent(notification);
}
/**
* 发起通知
*/
public static void notifyEvent(String key, String subKey, Map<String, Object> param) {
EventManager.getInstance().notifyEvent(key, subKey, param);
}
/**
* 注册扩展
*/
public static void registerExtension(String key, ITUIExtension extension) {
ExtensionManager.getInstance().registerExtension(key, extension);
}
/**
* 移除扩展
*/
public static void unRegisterExtension(String key, ITUIExtension extension) {
ExtensionManager.getInstance().unRegisterExtension(key, extension);
}
/**
* 获取扩展
*/
public static Map<String, Object> getExtensionInfo(String key, Map<String, Object> param) {
return ExtensionManager.getInstance().getExtensionInfo(key, param);
}
}
package com.tencent.qcloud.tuicore;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.tencent.imsdk.v2.V2TIMCallback;
import com.tencent.imsdk.v2.V2TIMManager;
import com.tencent.imsdk.v2.V2TIMSDKConfig;
import com.tencent.imsdk.v2.V2TIMSDKListener;
import com.tencent.imsdk.v2.V2TIMUserFullInfo;
import com.tencent.imsdk.v2.V2TIMValueCallback;
import com.tencent.qcloud.tuicore.util.ErrorMessageConverter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static com.tencent.imsdk.v2.V2TIMManager.V2TIM_STATUS_LOGINED;
/**
* 负责 IM 和 TRTC 的登录逻辑
*/
public class TUILogin {
private static final String TAG = TUILogin.class.getSimpleName();
private static Context appContext;
private static int sdkAppId = 0;
private static String userId;
private static String userSig;
/**
* IMSDK 初始化
*
* @param context 应用的上下文,一般为对应应用的 ApplicationContext
* @param sdkAppId 您在腾讯云注册应用时分配的sdkAppID
* @param config IMSDK 的相关配置项,一般使用默认即可,需特殊配置参考API文档
* @param listener IMSDK 初始化监听器
* @return true:成功;false:失败,如果 context 为空会返回失败
*/
public static boolean init(@NonNull Context context, int sdkAppId, @Nullable V2TIMSDKConfig config, @Nullable V2TIMSDKListener listener) {
if (TUILogin.sdkAppId != 0 && sdkAppId != TUILogin.sdkAppId) {
logout(null);
unInit();
}
TUILogin.appContext = context;
TUILogin.sdkAppId = sdkAppId;
V2TIMManager.getInstance().addIMSDKListener(new V2TIMSDKListener() {
@Override
public void onConnecting() {
if (listener != null) {
listener.onConnecting();
}
}
@Override
public void onConnectSuccess() {
if (listener != null) {
listener.onConnectSuccess();
}
}
@Override
public void onConnectFailed(int code, String error) {
if (listener != null) {
listener.onConnectFailed(code, ErrorMessageConverter.convertIMError(code, error));
}
}
@Override
public void onKickedOffline() {
if (listener != null) {
listener.onKickedOffline();
}
TUICore.notifyEvent(TUIConstants.TUILogin.EVENT_LOGIN_STATE_CHANGED,
TUIConstants.TUILogin.EVENT_SUB_KEY_USER_KICKED_OFFLINE, null);
}
@Override
public void onUserSigExpired() {
if (listener != null) {
listener.onUserSigExpired();
}
TUICore.notifyEvent(TUIConstants.TUILogin.EVENT_LOGIN_STATE_CHANGED,
TUIConstants.TUILogin.EVENT_SUB_KEY_USER_SIG_EXPIRED, null);
}
@Override
public void onSelfInfoUpdated(V2TIMUserFullInfo info) {
if (listener != null) {
listener.onSelfInfoUpdated(info);
}
TUIConfig.setSelfInfo(info);
notifyUserInfoChanged(info);
}
});
// 开始初始化 IMSDK,发送广播
TUICore.notifyEvent(TUIConstants.TUILogin.EVENT_IMSDK_INIT_STATE_CHANGED, TUIConstants.TUILogin.EVENT_SUB_KEY_START_INIT, null);
return V2TIMManager.getInstance().initSDK(context, sdkAppId, config);
}
/**
* 反初始化 IMSDK,释放资源
*/
public static void unInit() {
sdkAppId = 0;
// 开始反初始化 IMSDK,发送广播
TUICore.notifyEvent(TUIConstants.TUILogin.EVENT_IMSDK_INIT_STATE_CHANGED, TUIConstants.TUILogin.EVENT_SUB_KEY_START_UNINIT, null);
V2TIMManager.getInstance().unInitSDK();
TUIConfig.clearSelfInfo();
}
/**
* 用户登录
*
* @param userId 用户名
* @param userSig 从业务服务器获取的 userSig
* @param callback 登录是否成功的回调
*/
public static void login(@NonNull String userId, @NonNull String userSig, @Nullable V2TIMCallback callback) {
TUILogin.userId = userId;
TUILogin.userSig = userSig;
if (TextUtils.equals(userId, V2TIMManager.getInstance().getLoginUser()) && !TextUtils.isEmpty(userId)) {
if (callback != null) {
callback.onSuccess();
}
getUserInfo(userId);
return;
}
V2TIMManager.getInstance().login(userId, userSig, new V2TIMCallback() {
@Override
public void onSuccess() {
if (callback != null) {
callback.onSuccess();
}
getUserInfo(userId);
}
@Override
public void onError(int code, String desc) {
if (callback != null) {
callback.onError(code, ErrorMessageConverter.convertIMError(code, desc));
}
}
});
}
private static void getUserInfo(String userId) {
List<String> userIdList = new ArrayList<>();
userIdList.add(userId);
V2TIMManager.getInstance().getUsersInfo(userIdList, new V2TIMValueCallback<List<V2TIMUserFullInfo>>() {
@Override
public void onSuccess(List<V2TIMUserFullInfo> v2TIMUserFullInfos) {
if (v2TIMUserFullInfos.isEmpty()) {
Log.e(TAG, "get logined userInfo failed. list is empty");
return;
}
V2TIMUserFullInfo userFullInfo = v2TIMUserFullInfos.get(0);
TUIConfig.setSelfInfo(userFullInfo);
notifyUserInfoChanged(userFullInfo);
}
@Override
public void onError(int code, String desc) {
Log.e(TAG, "get logined userInfo failed. code : " + code + " desc : " + ErrorMessageConverter.convertIMError(code, desc));
}
});
}
private static void notifyUserInfoChanged(V2TIMUserFullInfo userFullInfo) {
HashMap<String, Object> param = new HashMap<>();
param.put(TUIConstants.TUILogin.SELF_ID, userFullInfo.getUserID());
param.put(TUIConstants.TUILogin.SELF_SIGNATURE, userFullInfo.getSelfSignature());
param.put(TUIConstants.TUILogin.SELF_NICK_NAME, userFullInfo.getNickName());
param.put(TUIConstants.TUILogin.SELF_FACE_URL, userFullInfo.getFaceUrl());
param.put(TUIConstants.TUILogin.SELF_BIRTHDAY, userFullInfo.getBirthday());
param.put(TUIConstants.TUILogin.SELF_ROLE, userFullInfo.getRole());
param.put(TUIConstants.TUILogin.SELF_GENDER, userFullInfo.getGender());
param.put(TUIConstants.TUILogin.SELF_LEVEL, userFullInfo.getLevel());
param.put(TUIConstants.TUILogin.SELF_ALLOW_TYPE, userFullInfo.getAllowType());
TUICore.notifyEvent(TUIConstants.TUILogin.EVENT_LOGIN_STATE_CHANGED,
TUIConstants.TUILogin.EVENT_SUB_KEY_USER_INFO_UPDATED, param);
}
/**
* 用户退出登录
*
* @param callback 退出登录是否成功的回调
*/
public static void logout(@Nullable V2TIMCallback callback) {
V2TIMManager.getInstance().logout(new V2TIMCallback() {
@Override
public void onSuccess() {
TUILogin.userId = null;
TUILogin.userSig = null;
if (callback != null) {
callback.onSuccess();
}
TUIConfig.clearSelfInfo();
}
@Override
public void onError(int code, String desc) {
if (callback != null) {
callback.onError(code, ErrorMessageConverter.convertIMError(code, desc));
}
}
});
}
/**
* 获取 sdkAppId,未初始化时 sdkAppId 默认为 0
* @return sdkAppId
*/
public static int getSdkAppId() {
return sdkAppId;
}
/**
* 获取 userId,未登录时 userId 默认为 null
* @return userId
*/
public static String getUserId() {
return userId;
}
/**
* 获取 userSig,未登录时 userSig 默认为 null
* @return userSig
*/
public static String getUserSig() {
return userSig;
}
/**
* 获取当前登录用户昵称
* @return 当前登录用户昵称
*/
public static String getNickName() {
return TUIConfig.getSelfNickName();
}
/**
* 获取当前登录用户头像
* @return 当前登录用户头像
*/
public static String getFaceUrl() {
return TUIConfig.getSelfFaceUrl();
}
/**
* 获取应用上下文,为初始化时传入的 applicationContext
* @return appContext
*/
public static Context getAppContext() {
return appContext;
}
/**
* 用户是否已经登录
* @return true:用户已经登录; false:用户尚未登录
*/
public static boolean isUserLogined() {
return V2TIMManager.getInstance().getLoginStatus() == V2TIM_STATUS_LOGINED;
}
/**
* 获取当前已经登录的用户 id,如果未初始化会返回 null
* @return userId
*/
public static String getLoginUser() {
return V2TIMManager.getInstance().getLoginUser();
}
}
\ No newline at end of file
package com.tencent.qcloud.tuicore;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.TypedValue;
import android.webkit.WebView;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.tencent.qcloud.tuicore.interfaces.ITUIThemeChangeable;
import com.tencent.qcloud.tuicore.util.TUIBuild;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/**
* 静态换肤、换语言管理
*/
public class TUIThemeManager {
private static final String TAG = TUIThemeManager.class.getSimpleName();
private static final String SP_THEME_AND_LANGUAGE_NAME = "TUIThemeAndLanguage";
private static final String SP_KEY_LANGUAGE = "language";
private static final String SP_KEY_THEME = "theme";
public static final int THEME_LIGHT = 0; // 轻量版 默认
public static final int THEME_LIVELY = 1; // 活泼版
public static final int THEME_SERIOUS = 2; // 严肃版
@IntDef({THEME_LIGHT, THEME_LIVELY, THEME_SERIOUS})
private @interface ThemeIds {}
private static final class ThemeManagerHolder {
private static final TUIThemeManager instance = new TUIThemeManager();
}
public static TUIThemeManager getInstance() {
return ThemeManagerHolder.instance;
}
private TUIThemeManager() {}
private boolean isInit = false;
private final List<Integer> lightThemeResIds = new ArrayList<>();
private final List<Integer> livelyThemeResIds = new ArrayList<>();
private final List<Integer> seriousThemeResIds = new ArrayList<>();
private int currentTheme = THEME_LIGHT;
private String currentLanguage = "";
static void setTheme(Context context) {
getInstance().setThemeInternal(context);
}
private void setThemeInternal(Context context) {
if (context == null) {
return;
}
Context appContext = context.getApplicationContext();
if (!isInit) {
isInit = true;
if (appContext instanceof Application) {
((Application) appContext).registerActivityLifecycleCallbacks(new ThemeAndLanguageCallback());
// 解决 Android 7 以上 WebView 导致切换语言失败的问题。
new WebView(appContext).destroy();
}
SharedPreferences sharedPreferences = context.getSharedPreferences(SP_THEME_AND_LANGUAGE_NAME, Context.MODE_PRIVATE);
currentLanguage = sharedPreferences.getString(SP_KEY_LANGUAGE, "");
currentTheme = sharedPreferences.getInt(SP_KEY_THEME, THEME_LIGHT);
// 语言只需要初始化一次
applyLanguage(appContext);
}
// 主题需要更新多次
applyTheme(appContext);
}
public static void addLightTheme(int resId) {
if (resId == 0) {
return;
}
if (getInstance().lightThemeResIds.contains(resId)) {
return;
}
getInstance().lightThemeResIds.add(resId);
}
public static void addLivelyTheme(int resId) {
if (resId == 0) {
return;
}
if (getInstance().livelyThemeResIds.contains(resId)) {
return;
}
getInstance().livelyThemeResIds.add(resId);
}
public static void addSeriousTheme(int resId) {
if (resId == 0) {
return;
}
if (getInstance().seriousThemeResIds.contains(resId)) {
return;
}
getInstance().seriousThemeResIds.add(resId);
}
public int getCurrentTheme() {
return currentTheme;
}
private void mergeTheme(Resources.Theme theme) {
if (theme == null) {
return;
}
List<Integer> currentThemeResIds = lightThemeResIds;
if (currentTheme == THEME_LIVELY) {
currentThemeResIds = livelyThemeResIds;
} else if (currentTheme == THEME_SERIOUS) {
currentThemeResIds = seriousThemeResIds;
}
for (Integer resId : currentThemeResIds) {
theme.applyStyle(resId, true);
}
}
public void changeLanguage(Context context, String language) {
if (context == null) {
return;
}
if (TextUtils.equals(language, currentLanguage)) {
return;
}
currentLanguage = language;
SharedPreferences sharedPreferences = context.getSharedPreferences(SP_THEME_AND_LANGUAGE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(SP_KEY_LANGUAGE, language);
editor.commit();
applyLanguage(context.getApplicationContext());
applyLanguage(context);
}
public void applyLanguage(Context context) {
if (context == null) {
return;
}
Locale locale = getLocale(context);
if ("en".equals(currentLanguage)) {
locale = Locale.ENGLISH;
} else if ("zh".equals(currentLanguage)) {
locale = Locale.CHINA;
}
Resources resources = context.getResources();
Configuration configuration = resources.getConfiguration();
configuration.locale = locale;
if (TUIBuild.getVersionInt() >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
configuration.setLocale(locale);
}
resources.updateConfiguration(configuration, null);
if (Build.VERSION.SDK_INT >= 25) {
context = context.createConfigurationContext(configuration);
context.getResources().updateConfiguration(configuration,
resources.getDisplayMetrics());
}
}
public String getCurrentLanguage() {
return currentLanguage;
}
private Locale getLocale(Context context) {
Locale locale;
if (TUIBuild.getVersionInt() < Build.VERSION_CODES.N) {
locale = context.getResources().getConfiguration().locale;
} else {
locale = context.getResources().getConfiguration().getLocales().get(0);
}
return locale;
}
public void changeTheme(Context context, @ThemeIds int themeId) {
if (context == null) {
return;
}
if (themeId == currentTheme) {
return;
}
currentTheme = themeId;
SharedPreferences sharedPreferences = context.getSharedPreferences(SP_THEME_AND_LANGUAGE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putInt(SP_KEY_THEME, themeId);
editor.commit();
applyTheme(context.getApplicationContext());
applyTheme(context);
}
/**
* 当前 Activity 或者 Application 应用主题
* @param context 一般为 Application 或者 Activity
*/
private void applyTheme(Context context) {
if (context == null) {
return;
}
Resources.Theme theme = context.getTheme();
if (theme == null) {
theme = context.getTheme();
}
mergeTheme(theme);
}
/**
* 获取参与换肤的资源 id
* @param context 一般为当前界面的 Activity,此 Activity 实现了 ITUIThemeChangeable 接口
* @param attrId attr 自定义的要变换主题的 attr
* @return 当前主题下的资源 id
*/
public static int getAttrResId(Context context, int attrId) {
if (context == null || attrId == 0) {
return 0;
}
TypedValue typedValue = new TypedValue();
context.getTheme().resolveAttribute(attrId, typedValue, true);
return typedValue.resourceId;
}
static class ThemeAndLanguageCallback implements Application.ActivityLifecycleCallbacks {
@Override
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
// 如果 Activity 支持换肤则设置主题
if (activity instanceof ITUIThemeChangeable) {
TUIThemeManager.getInstance().applyTheme(activity);
}
TUIThemeManager.getInstance().applyLanguage(activity);
}
@Override
public void onActivityStarted(@NonNull Activity activity) {
}
@Override
public void onActivityResumed(@NonNull Activity activity) {
}
@Override
public void onActivityPaused(@NonNull Activity activity) {
}
@Override
public void onActivityStopped(@NonNull Activity activity) {
}
@Override
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
}
@Override
public void onActivityDestroyed(@NonNull Activity activity) {
}
}
}
package com.tencent.qcloud.tuicore.calling.basic;
public interface AvatarConstant {
String USER_AVATAR_ARRAY [] = {
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar1.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar2.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar3.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar4.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar5.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar6.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar7.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar8.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar9.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar10.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar11.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar12.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar13.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar14.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar15.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar16.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar17.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar18.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar19.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar20.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar21.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar22.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar23.png",
"https://liteav.sdk.qcloud.com/app/res/picture/voiceroom/avatar/user_avatar24.png",
};
}
package com.tencent.qcloud.tuicore.calling.basic;
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 = 15; //TRTC默认图片圆角为15dp
public static void clear(Context context, ImageView imageView) {
Glide.with(context).clear(imageView);
}
public static void clear(Context context) {
Glide.with(context).pauseRequests();
}
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 loadImageThumbnail(Context context, ImageView imageView, String url, @DrawableRes int resourceId, int radius) {
Glide.with(context).load(url)
.apply(new RequestOptions().placeholder(resourceId).error(resourceId).centerCrop()
.transform(new GlideRoundTransform(imageView.getContext(), radius)))
.thumbnail(loadTransform(imageView.getContext(), resourceId, radius))
.into(imageView);
}
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) {
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment