diff --git a/sample-videochat-kotlin/app/build.gradle b/sample-videochat-kotlin/app/build.gradle
index 3d08a2c63..310338da7 100644
--- a/sample-videochat-kotlin/app/build.gradle
+++ b/sample-videochat-kotlin/app/build.gradle
@@ -4,7 +4,7 @@ buildscript {
mavenCentral()
}
dependencies {
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinGradlePluginVersion"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31"
}
}
@@ -29,26 +29,26 @@ android {
compileSdkVersion 31
buildToolsVersion "31.0.0"
- flavorDimensions dimensionDefault
+ flavorDimensions "default"
defaultConfig {
applicationId "com.quickblox.sample.videochat.kotlin"
minSdkVersion 21
targetSdkVersion 31
- versionCode 405000
- versionName '4.0.5'
+ versionCode 410000
+ versionName '4.1.0'
multiDexEnabled true
}
productFlavors {
dev {
- dimension dimensionDefault
+ dimension "default"
buildConfigField('boolean', "IS_QA", "false")
buildConfigField("int", "VERSION_QA_CODE", versionQACode.toString())
}
qa {
- dimension dimensionDefault
+ dimension "default"
buildConfigField("boolean", "IS_QA", "true")
buildConfigField("int", "VERSION_QA_CODE", versionQACode.toString())
}
@@ -92,14 +92,14 @@ android {
}
dependencies {
- implementation "com.quickblox:quickblox-android-sdk-videochat-webrtc:$qbSdkVersion"
- implementation "com.quickblox:quickblox-android-sdk-messages:$qbSdkVersion"
- implementation "com.google.firebase:firebase-core:$firebaseCoreVersion"
- implementation "com.google.android.material:material:$materialVersion"
- implementation "com.github.johnkil.android-robototextview:robototextview:$robotoTextViewVersion"
- implementation "androidx.fragment:fragment-ktx:$fragmentAndroidXVersion"
- implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleViewmodelAndroidXVersion"
- implementation "androidx.core:core-ktx:$coreKtxVersion"
+ implementation 'com.quickblox:quickblox-android-sdk-videochat-webrtc:3.10.1'
+ implementation 'com.quickblox:quickblox-android-sdk-messages:3.10.1'
+ implementation 'com.google.firebase:firebase-core:21.1.0'
+ implementation 'com.google.android.material:material:1.6.1'
+ implementation 'com.github.johnkil.android-robototextview:robototextview:4.0.0'
+ implementation 'androidx.fragment:fragment-ktx:1.5.2'
+ implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
+ implementation 'androidx.core:core-ktx:1.8.0'
}
apply from: "../artifacts.gradle"
diff --git a/sample-videochat-kotlin/app/proguard-rules.pro b/sample-videochat-kotlin/app/proguard-rules.pro
index 7c835c9ff..6eb13999d 100644
--- a/sample-videochat-kotlin/app/proguard-rules.pro
+++ b/sample-videochat-kotlin/app/proguard-rules.pro
@@ -41,4 +41,7 @@
-keep class org.webrtc.** { *; }
#google gms
--keep class com.google.android.gms.** { *; }
\ No newline at end of file
+-keep class com.google.android.gms.** { *; }
+
+#json
+-keep class org.json.** { *; }
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/AndroidManifest.xml b/sample-videochat-kotlin/app/src/main/AndroidManifest.xml
index 1f9e4169f..4ca7e0b71 100644
--- a/sample-videochat-kotlin/app/src/main/AndroidManifest.xml
+++ b/sample-videochat-kotlin/app/src/main/AndroidManifest.xml
@@ -37,11 +37,6 @@
android:name=".activities.LoginActivity"
android:screenOrientation="portrait" />
-
-
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/App.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/App.kt
index 81bd0a966..11b0d0e27 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/App.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/App.kt
@@ -4,10 +4,10 @@ import android.app.Application
import com.quickblox.auth.session.QBSettings
import com.quickblox.sample.videochat.kotlin.db.DbHelper
-//User default credentials
+// user default credentials
const val DEFAULT_USER_PASSWORD = "quickblox"
-//App credentials
+// app credentials
private const val APPLICATION_ID = ""
private const val AUTH_KEY = ""
private const val AUTH_SECRET = ""
@@ -42,7 +42,7 @@ class App : Application() {
QBSettings.getInstance().init(applicationContext, APPLICATION_ID, AUTH_KEY, AUTH_SECRET)
QBSettings.getInstance().accountKey = ACCOUNT_KEY
- // Uncomment and put your Api and Chat servers endpoints if you want to point the sample
+ // uncomment and put your Api and Chat servers endpoints if you want to point the sample
// against your own server.
//
// QBSettings.getInstance().setEndpoints("https://your_api_endpoint.com", "your_chat_endpoint", ServiceZone.PRODUCTION);
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/AppInfoActivity.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/AppInfoActivity.kt
index 626995549..b70a3ddbe 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/AppInfoActivity.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/AppInfoActivity.kt
@@ -71,7 +71,7 @@ class AppInfoActivity : AppCompatActivity() {
appQAVersionTextView.setText(spannable, TextView.BufferType.SPANNABLE)
appQAVersionTextView.visibility = View.VISIBLE
- findViewById(R.id.text_qa_version_title).visibility = View.VISIBLE
+ findViewById(R.id.text_qa_version_title).visibility = View.VISIBLE
}
}
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/BaseActivity.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/BaseActivity.kt
index a6a88b1a3..2ad1c561f 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/BaseActivity.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/BaseActivity.kt
@@ -11,23 +11,19 @@ import androidx.core.content.ContextCompat
import com.quickblox.sample.videochat.kotlin.R
import com.quickblox.sample.videochat.kotlin.utils.showErrorSnackbar
-
abstract class BaseActivity : AppCompatActivity() {
private var progressDialog: ProgressDialog? = null
-
internal fun showProgressDialog(@StringRes messageId: Int) {
if (progressDialog == null) {
progressDialog = ProgressDialog(this)
- progressDialog!!.isIndeterminate = true
- progressDialog!!.setCancelable(false)
- progressDialog!!.setCanceledOnTouchOutside(false)
-
- // Disable the back button
- progressDialog!!.setOnKeyListener(KeyEventListener())
+ progressDialog?.isIndeterminate = true
+ progressDialog?.setCancelable(false)
+ progressDialog?.setCanceledOnTouchOutside(false)
+ progressDialog?.setOnKeyListener(KeyEventListener())
}
- progressDialog!!.setMessage(getString(messageId))
- progressDialog!!.show()
+ progressDialog?.setMessage(getString(messageId))
+ progressDialog?.show()
}
override fun onPause() {
@@ -36,16 +32,14 @@ abstract class BaseActivity : AppCompatActivity() {
}
internal fun hideProgressDialog() {
- if (progressDialog != null && progressDialog?.isShowing == true) {
- progressDialog!!.dismiss()
+ if (progressDialog?.isShowing == true) {
+ progressDialog?.dismiss()
}
}
- protected fun showErrorSnackbar(@StringRes resId: Int, e: Exception, clickListener: View.OnClickListener) {
+ protected fun showErrorSnackbar(@StringRes resId: Int, e: Exception?, clickListener: View.OnClickListener) {
val rootView = window.decorView.findViewById(android.R.id.content)
- if (rootView != null) {
- showErrorSnackbar(rootView, resId, e, R.string.dlg_retry, clickListener)
- }
+ showErrorSnackbar(rootView, resId, e, R.string.dlg_retry, clickListener)
}
protected fun checkPermissions(permissions: Array): Boolean {
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/CallActivity.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/CallActivity.kt
index 54197eaae..0a12484df 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/CallActivity.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/CallActivity.kt
@@ -2,6 +2,7 @@ package com.quickblox.sample.videochat.kotlin.activities
import android.annotation.TargetApi
import android.app.Activity
+import android.app.KeyguardManager
import android.content.*
import android.net.Uri
import android.os.*
@@ -9,19 +10,18 @@ import android.preference.PreferenceManager
import android.provider.Settings
import android.util.Log
import android.view.View
-import android.view.ViewGroup
+import android.view.WindowManager
+import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.TextView
-import com.quickblox.chat.QBChatService
import com.quickblox.core.QBEntityCallbackImpl
import com.quickblox.sample.videochat.kotlin.R
import com.quickblox.sample.videochat.kotlin.db.QbUsersDbManager
import com.quickblox.sample.videochat.kotlin.fragments.*
import com.quickblox.sample.videochat.kotlin.services.CallService
-import com.quickblox.sample.videochat.kotlin.services.LoginService
-import com.quickblox.sample.videochat.kotlin.services.ONE_OPPONENT
-import com.quickblox.sample.videochat.kotlin.util.loadUsersByIds
+import com.quickblox.sample.videochat.kotlin.services.MIN_OPPONENT_SIZE
import com.quickblox.sample.videochat.kotlin.utils.*
+import com.quickblox.users.QBUsers
import com.quickblox.users.model.QBUser
import com.quickblox.videochat.webrtc.*
import com.quickblox.videochat.webrtc.callbacks.QBRTCClientSessionCallbacks
@@ -43,15 +43,16 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
private var TAG = CallActivity::class.java.simpleName
- private val currentCallStateCallbackList = ArrayList()
+ private val callStateListeners = hashSetOf()
+ private val updateOpponentsListeners = hashSetOf()
+ private val callTimeUpdateListeners = hashSetOf()
private lateinit var showIncomingCallWindowTaskHandler: Handler
private var connectionListener: ConnectionListenerImpl? = null
private lateinit var callServiceConnection: ServiceConnection
private lateinit var showIncomingCallWindowTask: Runnable
- private lateinit var sharedPref: SharedPreferences
- private var opponentsIdsList: List? = null
+ private var opponentIds: List? = null
private lateinit var callService: CallService
-
+ private var connectionView: LinearLayout? = null
private var isInComingCall: Boolean = false
private var isVideoCall: Boolean = false
@@ -69,21 +70,38 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
+ setShowWhenLocked(true)
+ setTurnScreenOn(true)
+ val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
+ keyguardManager.requestDismissKeyguard(this, null)
+ } else {
+ this.window.addFlags(
+ WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or
+ WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
+ WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+ )
+ }
+ connectionView = View.inflate(this, R.layout.connection_popup, null) as LinearLayout
}
private fun initScreen() {
callService.setCallTimerCallback(CallTimerCallback())
isVideoCall = callService.isVideoCall()
- opponentsIdsList = callService.getOpponents()
+ opponentIds = callService.getOpponents()
- PreferenceManager.setDefaultValues(this, R.xml.preferences, false)
- sharedPref = PreferenceManager.getDefaultSharedPreferences(this)
+ applyMediaSettings()
- initSettingsStrategy()
addListeners()
- if (callService.isCallMode()) {
+ isInComingCall = if (intent != null && intent.extras != null) {
+ intent?.extras?.getBoolean(EXTRA_IS_INCOMING_CALL) ?: false
+ } else {
+ SharedPrefsHelper.get(EXTRA_IS_INCOMING_CALL, false)
+ }
+
+ if (callService.isConnectedCall()) {
checkPermission()
if (callService.isSharingScreenState()) {
startScreenSharing(null)
@@ -91,12 +109,6 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
}
addConversationFragment(isInComingCall)
} else {
- if (intent != null && intent.extras != null) {
- isInComingCall = intent?.extras?.getBoolean(EXTRA_IS_INCOMING_CALL) ?: true
- } else {
- isInComingCall = SharedPrefsHelper.get(EXTRA_IS_INCOMING_CALL, false)
- }
-
if (!isInComingCall) {
callService.playRingtone()
}
@@ -128,6 +140,7 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
Log.i(TAG, "onActivityResult requestCode=$requestCode, resultCode= $resultCode")
if (resultCode == EXTRA_LOGIN_RESULT_CODE) {
data?.let {
@@ -163,9 +176,9 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
private fun startSuitableFragment(isInComingCall: Boolean) {
val session = WebRtcSessionManager.getCurrentSession()
if (session != null) {
+ loadAbsentUsers()
if (isInComingCall) {
initIncomingCallTask()
- startLoadAbsentUsers()
addIncomeCallFragment()
checkPermission()
} else {
@@ -224,11 +237,11 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
startActivityForResult(intent, REQUEST_PERMISSION_SETTING)
}
- private fun startLoadAbsentUsers() {
+ private fun loadAbsentUsers() {
val usersFromDb = QbUsersDbManager.allUsers
val allParticipantsOfCall = ArrayList()
- opponentsIdsList?.let {
+ opponentIds?.let {
allParticipantsOfCall.addAll(it)
}
@@ -248,20 +261,14 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
idsNotLoadedUsers.add(userId)
}
}
-
- if (!idsNotLoadedUsers.isEmpty()) {
- loadUsersByIds(idsNotLoadedUsers, object : QBEntityCallbackImpl>() {
- override fun onSuccess(users: ArrayList, params: Bundle) {
- QbUsersDbManager.saveAllUsers(users, false)
- notifyCallStateListenersNeedUpdateOpponentsList(users)
- }
- })
- }
- }
-
- private fun initSettingsStrategy() {
- opponentsIdsList?.let {
- setSettingsStrategy(it, sharedPref, this)
+ if (idsNotLoadedUsers.isNotEmpty()) {
+ QBUsers.getUsersByIDs(idsNotLoadedUsers, null)
+ .performAsync(object : QBEntityCallbackImpl>() {
+ override fun onSuccess(users: ArrayList, params: Bundle) {
+ QbUsersDbManager.saveAllUsers(users, false)
+ notifyOpponentsUpdated(users)
+ }
+ })
}
}
@@ -345,27 +352,31 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
)
}
- private fun showNotificationPopUp(text: Int, show: Boolean) {
+ private fun showConnectionPopUp() {
runOnUiThread {
- val connectionView = View.inflate(this, R.layout.connection_popup, null) as LinearLayout
- if (show) {
- (connectionView.findViewById(R.id.notification) as TextView).setText(text)
- if (connectionView.parent == null) {
- (this@CallActivity.findViewById(R.id.fragment_container) as ViewGroup).addView(connectionView)
- }
- } else {
- (this@CallActivity.findViewById(R.id.fragment_container) as ViewGroup).removeView(connectionView)
+ val fragmentContainer: FrameLayout = findViewById(R.id.fragment_container)
+ val connectionNotificationView: TextView? = connectionView?.findViewById(R.id.notification)
+ connectionNotificationView?.setText(R.string.connection_was_lost)
+ if (connectionView?.parent == null) {
+ fragmentContainer.addView(connectionView)
}
}
}
+ private fun hideConnectionPopUp() {
+ runOnUiThread {
+ val fragmentContainer: FrameLayout = findViewById(R.id.fragment_container)
+ fragmentContainer.removeView(connectionView)
+ }
+ }
+
private inner class ConnectionListenerImpl : AbstractConnectionListener() {
override fun connectionClosedOnError(e: Exception?) {
- showNotificationPopUp(R.string.connection_was_lost, true)
+ showConnectionPopUp()
}
override fun reconnectionSuccessful() {
- showNotificationPopUp(R.string.connection_was_lost, false)
+ hideConnectionPopUp()
}
}
@@ -374,7 +385,7 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
}
override fun onConnectedToUser(session: QBRTCSession?, userId: Int?) {
- notifyCallStateListenersCallStarted()
+ notifyCallStarted()
if (isInComingCall) {
stopIncomeCallTimer()
}
@@ -398,14 +409,14 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
override fun onSessionStartClose(session: QBRTCSession?) {
if (callService.isCurrentSession(session)) {
callService.removeSessionStateListener(this)
- notifyCallStateListenersCallStopped()
+ notifyCallStopped()
}
}
override fun onReceiveHangUpFromUser(session: QBRTCSession?, userId: Int?, map: MutableMap?) {
if (callService.isCurrentSession(session)) {
val numberOpponents = session?.opponents?.size
- if (numberOpponents == ONE_OPPONENT) {
+ if (numberOpponents == MIN_OPPONENT_SIZE) {
hangUpCurrentSession()
}
val participant = QbUsersDbManager.getUserById(userId)
@@ -436,9 +447,7 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
}
override fun onCallRejectByUser(session: QBRTCSession?, userId: Int?, map: MutableMap?) {
- if (callService.isCurrentSession(session)) {
- callService.stopRingtone()
- }
+ // empty
}
override fun onAcceptCurrentSession() {
@@ -505,14 +514,28 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
callService.removeSessionEventsListener(eventsCallback)
}
- override fun addCurrentCallStateListener(currentCallStateCallback: CurrentCallStateCallback?) {
- currentCallStateCallback?.let {
- currentCallStateCallbackList.add(it)
- }
+ override fun addCallStateListener(callStateListener: CallStateListener) {
+ callStateListeners.add(callStateListener)
+ }
+
+ override fun removeCallStateListener(callStateListener: CallStateListener) {
+ callStateListeners.remove(callStateListener)
+ }
+
+ override fun addUpdateOpponentsListener(updateOpponentsListener: UpdateOpponentsListener) {
+ updateOpponentsListeners.add(updateOpponentsListener)
+ }
+
+ override fun removeUpdateOpponentsListener(updateOpponentsListener: UpdateOpponentsListener) {
+ updateOpponentsListeners.remove(updateOpponentsListener)
+ }
+
+ override fun addCallTimeUpdateListener(callTimeUpdateListener: CallTimeUpdateListener) {
+ callTimeUpdateListeners.add(callTimeUpdateListener)
}
- override fun removeCurrentCallStateListener(currentCallStateCallback: CurrentCallStateCallback?) {
- currentCallStateCallbackList.remove(currentCallStateCallback)
+ override fun removeCallTimeUpdateListener(callTimeUpdateListener: CallTimeUpdateListener) {
+ callTimeUpdateListeners.remove(callTimeUpdateListener)
}
override fun addOnChangeAudioDeviceListener(onChangeDynamicCallback: OnChangeAudioDevice?) {
@@ -563,8 +586,8 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
return callService.isMediaStreamManagerExist()
}
- override fun isCallState(): Boolean {
- return callService.isCallMode()
+ override fun isConnectedCall(): Boolean {
+ return callService.isConnectedCall()
}
override fun getVideoTrackMap(): MutableMap {
@@ -577,30 +600,30 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
override fun onStopPreview() {
callService.stopScreenSharing()
- addConversationFragment(false)
+ addConversationFragment(isInComingCall)
}
- private fun notifyCallStateListenersCallStarted() {
- for (callback in currentCallStateCallbackList) {
- callback.onCallStarted()
+ private fun notifyCallStarted() {
+ for (listener in callStateListeners) {
+ listener.startedCall()
}
}
- private fun notifyCallStateListenersCallStopped() {
- for (callback in currentCallStateCallbackList) {
- callback.onCallStopped()
+ private fun notifyCallStopped() {
+ for (listener in callStateListeners) {
+ listener.stoppedCall()
}
}
- private fun notifyCallStateListenersNeedUpdateOpponentsList(newUsers: ArrayList) {
- for (callback in currentCallStateCallbackList) {
- callback.onOpponentsListUpdated(newUsers)
+ private fun notifyOpponentsUpdated(opponents: ArrayList) {
+ for (listener in updateOpponentsListeners) {
+ listener.updatedOpponents(opponents)
}
}
- private fun notifyCallStateListenersCallTime(callTime: String) {
- for (callback in currentCallStateCallbackList) {
- callback.onCallTimeUpdate(callTime)
+ private fun notifyCallTimeUpdated(callTime: String) {
+ for (listener in callTimeUpdateListeners) {
+ listener.updatedCallTime(callTime)
}
}
@@ -613,29 +636,17 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
val binder = service as CallService.CallServiceBinder
callService = binder.getService()
if (callService.currentSessionExist()) {
- // we have already currentSession == null, so it's no reason to do further initialization
- if (QBChatService.getInstance().isLoggedIn) {
- initScreen()
- } else {
- login()
- }
+ initScreen();
} else {
finish()
}
}
-
- private fun login() {
- val qbUser = SharedPrefsHelper.getQbUser()
- val tempIntent = Intent(this@CallActivity, LoginService::class.java)
- val pendingIntent = createPendingResult(EXTRA_LOGIN_RESULT_CODE, tempIntent, 0)
- LoginService.start(this@CallActivity, qbUser, pendingIntent)
- }
}
private inner class CallTimerCallback : CallService.CallTimerListener {
override fun onCallTimeUpdate(time: String) {
runOnUiThread {
- notifyCallStateListenersCallTime(time)
+ notifyCallTimeUpdated(time)
}
}
}
@@ -644,13 +655,17 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
fun audioDeviceChanged(newAudioDevice: AppRTCAudioManager.AudioDevice)
}
- interface CurrentCallStateCallback {
- fun onCallStarted()
+ interface CallStateListener {
+ fun startedCall()
- fun onCallStopped()
+ fun stoppedCall()
+ }
- fun onOpponentsListUpdated(newUsers: ArrayList)
+ interface UpdateOpponentsListener {
+ fun updatedOpponents(updatedOpponents: ArrayList)
+ }
- fun onCallTimeUpdate(time: String)
+ interface CallTimeUpdateListener {
+ fun updatedCallTime(time: String)
}
}
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/LoginActivity.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/LoginActivity.kt
index 15f9d8a4b..b98285241 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/LoginActivity.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/LoginActivity.kt
@@ -13,8 +13,6 @@ import com.quickblox.core.exception.QBResponseException
import com.quickblox.sample.videochat.kotlin.DEFAULT_USER_PASSWORD
import com.quickblox.sample.videochat.kotlin.R
import com.quickblox.sample.videochat.kotlin.services.LoginService
-import com.quickblox.sample.videochat.kotlin.util.signInUser
-import com.quickblox.sample.videochat.kotlin.util.signUp
import com.quickblox.sample.videochat.kotlin.utils.*
import com.quickblox.users.QBUsers
import com.quickblox.users.model.QBUser
@@ -22,9 +20,8 @@ import com.quickblox.users.model.QBUser
const val ERROR_LOGIN_ALREADY_TAKEN_HTTP_STATUS = 422
class LoginActivity : BaseActivity() {
-
private lateinit var userLoginEditText: EditText
- private lateinit var userFullNameEditText: EditText
+ private lateinit var userDisplayNameEditText: EditText
private lateinit var user: QBUser
@@ -45,11 +42,11 @@ class LoginActivity : BaseActivity() {
userLoginEditText = findViewById(R.id.userLoginEditText)
userLoginEditText.addTextChangedListener(LoginEditTextWatcher(userLoginEditText))
- userFullNameEditText = findViewById(R.id.userFullNameEditText)
- userFullNameEditText.addTextChangedListener(LoginEditTextWatcher(userFullNameEditText))
+ userDisplayNameEditText = findViewById(R.id.userDisplayNameEditText)
+ userDisplayNameEditText.addTextChangedListener(LoginEditTextWatcher(userDisplayNameEditText))
}
- override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.activity_login, menu)
return true
}
@@ -57,41 +54,37 @@ class LoginActivity : BaseActivity() {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.menu_login_user_done -> {
- if (isEnteredUserNameValid() && isEnteredRoomNameValid()) {
- hideKeyboard()
- val user = createUserWithEnteredData()
- signUpNewUser(user)
+ val isNotValidLogin = !isLoginValid(userLoginEditText.text.toString())
+ if (isNotValidLogin) {
+ userLoginEditText.error = getString(R.string.error_login)
+ return false
+ }
+
+ val isNotValidDisplayName = !isDisplayNameValid(userDisplayNameEditText.text.toString())
+ if (isNotValidDisplayName) {
+ userDisplayNameEditText.error = getString(R.string.error_display_name)
+ return false
}
+ hideKeyboard(userDisplayNameEditText)
+ val user = createUser()
+ signUp(user)
return true
}
else -> super.onOptionsItemSelected(item)
}
}
- private fun isEnteredUserNameValid(): Boolean {
- return isLoginValid(this, userLoginEditText)
- }
-
- private fun isEnteredRoomNameValid(): Boolean {
- return isFoolNameValid(this, userFullNameEditText)
- }
-
- private fun hideKeyboard() {
- hideKeyboard(userLoginEditText)
- hideKeyboard(userFullNameEditText)
- }
-
- private fun signUpNewUser(newUser: QBUser) {
+ private fun signUp(user: QBUser) {
showProgressDialog(R.string.dlg_creating_new_user)
- signUp(newUser, object : QBEntityCallback {
+ QBUsers.signUp(user).performAsync(object : QBEntityCallback {
override fun onSuccess(result: QBUser, params: Bundle) {
- SharedPrefsHelper.saveQbUser(newUser)
+ SharedPrefsHelper.saveCurrentUser(user)
loginToChat(result)
}
override fun onError(e: QBResponseException) {
if (e.httpStatusCode == ERROR_LOGIN_ALREADY_TAKEN_HTTP_STATUS) {
- signInCreatedUser(newUser)
+ loginToRest(user)
} else {
hideProgressDialog()
longToast(R.string.sign_up_error)
@@ -100,20 +93,20 @@ class LoginActivity : BaseActivity() {
})
}
- private fun loginToChat(qbUser: QBUser) {
- qbUser.password = DEFAULT_USER_PASSWORD
- user = qbUser
- startLoginService(qbUser)
+ private fun loginToChat(user: QBUser) {
+ user.password = DEFAULT_USER_PASSWORD
+ this.user = user
+ startLoginService(user)
}
- private fun createUserWithEnteredData(): QBUser {
- val qbUser = QBUser()
+ private fun createUser(): QBUser {
+ val user = QBUser()
val userLogin = userLoginEditText.text.toString()
- val userFullName = userFullNameEditText.text.toString()
- qbUser.login = userLogin
- qbUser.fullName = userFullName
- qbUser.password = DEFAULT_USER_PASSWORD
- return qbUser
+ val userFullName = userDisplayNameEditText.text.toString()
+ user.login = userLogin
+ user.fullName = userFullName
+ user.password = DEFAULT_USER_PASSWORD
+ return user
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
@@ -121,31 +114,30 @@ class LoginActivity : BaseActivity() {
if (resultCode == EXTRA_LOGIN_RESULT_CODE) {
hideProgressDialog()
- var isLoginSuccess = false
- data?.let {
- isLoginSuccess = it.getBooleanExtra(EXTRA_LOGIN_RESULT, false)
- }
-
- var errorMessage: String? = getString(R.string.unknown_error)
+ var isLoginSuccessInChat = false
data?.let {
- errorMessage = it.getStringExtra(EXTRA_LOGIN_ERROR_MESSAGE)
+ isLoginSuccessInChat = it.getBooleanExtra(EXTRA_LOGIN_RESULT, false)
}
- if (isLoginSuccess) {
- SharedPrefsHelper.saveQbUser(user)
- signInCreatedUser(user)
+ if (isLoginSuccessInChat) {
+ SharedPrefsHelper.saveCurrentUser(user)
+ loginToRest(user)
} else {
+ var errorMessage: String? = getString(R.string.unknown_error)
+ data?.let {
+ errorMessage = it.getStringExtra(EXTRA_LOGIN_ERROR_MESSAGE)
+ }
longToast(getString(R.string.login_chat_login_error) + errorMessage)
userLoginEditText.setText(user.login)
- userFullNameEditText.setText(user.fullName)
+ userDisplayNameEditText.setText(user.fullName)
}
}
}
- private fun signInCreatedUser(user: QBUser) {
- signInUser(user, object : QBEntityCallback {
+ private fun loginToRest(user: QBUser) {
+ QBUsers.signIn(user).performAsync(object : QBEntityCallback {
override fun onSuccess(result: QBUser, params: Bundle) {
- SharedPrefsHelper.saveQbUser(user)
+ SharedPrefsHelper.saveCurrentUser(user)
updateUserOnServer(user)
}
@@ -159,7 +151,7 @@ class LoginActivity : BaseActivity() {
private fun updateUserOnServer(user: QBUser) {
user.password = null
QBUsers.updateUser(user).performAsync(object : QBEntityCallback {
- override fun onSuccess(updUser: QBUser?, params: Bundle?) {
+ override fun onSuccess(user: QBUser?, params: Bundle?) {
hideProgressDialog()
OpponentsActivity.start(this@LoginActivity)
finish()
@@ -179,7 +171,7 @@ class LoginActivity : BaseActivity() {
private fun startLoginService(qbUser: QBUser) {
val tempIntent = Intent(this, LoginService::class.java)
val pendingIntent = createPendingResult(EXTRA_LOGIN_RESULT_CODE, tempIntent, 0)
- LoginService.start(this, qbUser, pendingIntent)
+ LoginService.loginToChatAndInitRTCClient(this, qbUser, pendingIntent)
}
private inner class LoginEditTextWatcher internal constructor(private val editText: EditText) :
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/OpponentsActivity.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/OpponentsActivity.kt
index 356ad0ef2..2aadaa5bc 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/OpponentsActivity.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/OpponentsActivity.kt
@@ -9,7 +9,6 @@ import android.text.TextUtils
import android.util.Log
import android.view.Menu
import android.view.MenuItem
-import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.quickblox.chat.QBChatService
@@ -22,16 +21,15 @@ import com.quickblox.messages.services.SubscribeService
import com.quickblox.sample.videochat.kotlin.R
import com.quickblox.sample.videochat.kotlin.adapters.UsersAdapter
import com.quickblox.sample.videochat.kotlin.db.QbUsersDbManager
+import com.quickblox.sample.videochat.kotlin.executor.Executor
+import com.quickblox.sample.videochat.kotlin.executor.ExecutorTask
import com.quickblox.sample.videochat.kotlin.services.CallService
import com.quickblox.sample.videochat.kotlin.services.LoginService
-import com.quickblox.sample.videochat.kotlin.util.signOut
import com.quickblox.sample.videochat.kotlin.utils.*
import com.quickblox.users.QBUsers
import com.quickblox.users.model.QBUser
import com.quickblox.videochat.webrtc.QBRTCClient
import com.quickblox.videochat.webrtc.QBRTCTypes
-import kotlin.Exception
-
private const val PER_PAGE_SIZE_100 = 100
private const val ORDER_RULE = "order"
@@ -61,7 +59,7 @@ class OpponentsActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_select_users)
- currentUser = SharedPrefsHelper.getQbUser()
+ currentUser = SharedPrefsHelper.getCurrentUser()
initDefaultActionBar()
initUI()
startLoginService()
@@ -121,7 +119,7 @@ class OpponentsActivity : BaseActivity() {
}
if (currentPage == 1) {
- initUsersList()
+ initOpponents()
} else {
usersAdapter?.addUsers(qbUsers)
}
@@ -136,7 +134,9 @@ class OpponentsActivity : BaseActivity() {
hideProgressDialog()
isLoading = false
currentPage -= 1
- showErrorSnackbar(R.string.loading_users_error, e, View.OnClickListener { loadUsers() })
+ showErrorSnackbar(R.string.loading_users_error, e) {
+ loadUsers()
+ }
}
}
})
@@ -146,12 +146,13 @@ class OpponentsActivity : BaseActivity() {
usersRecyclerView = findViewById(R.id.list_select_users)
}
- private fun initUsersList() {
- val currentOpponentsList = QbUsersDbManager.allUsers
- currentOpponentsList.remove(SharedPrefsHelper.getQbUser())
+ private fun initOpponents() {
+ val opponents = QbUsersDbManager.allUsers
+ opponents.remove(SharedPrefsHelper.getCurrentUser())
if (usersAdapter == null) {
- usersAdapter = UsersAdapter(this, currentOpponentsList)
- usersAdapter!!.setSelectedItemsCountsChangedListener(object : UsersAdapter.SelectedItemsCountsChangedListener {
+ usersAdapter = UsersAdapter(this, opponents)
+ usersAdapter?.setSelectedItemsCountsChangedListener(object :
+ UsersAdapter.SelectedItemsCountsChangedListener {
override fun onCountSelectedItemsChanged(count: Int) {
updateActionBar(count)
}
@@ -161,7 +162,7 @@ class OpponentsActivity : BaseActivity() {
usersRecyclerView.adapter = usersAdapter
usersRecyclerView.addOnScrollListener(ScrollListener(usersRecyclerView.layoutManager as LinearLayoutManager))
} else {
- usersAdapter!!.updateUsersList(currentOpponentsList)
+ usersAdapter?.updateUsersList(opponents)
}
}
@@ -183,12 +184,10 @@ class OpponentsActivity : BaseActivity() {
loadUsers()
return true
}
- R.id.settings -> {
- SettingsActivity.start(this)
- return true
- }
R.id.log_out -> {
- unsubscribeFromPushesAndLogout()
+ unsubscribeFromPushes(callback = {
+ logout()
+ })
return true
}
R.id.start_video_call -> {
@@ -227,67 +226,82 @@ class OpponentsActivity : BaseActivity() {
}
private fun startLoginService() {
- if (SharedPrefsHelper.hasQbUser()) {
- LoginService.start(this, SharedPrefsHelper.getQbUser())
+ if (SharedPrefsHelper.hasCurrentUser()) {
+ LoginService.loginToChatAndInitRTCClient(this, SharedPrefsHelper.getCurrentUser())
}
}
private fun startCall(isVideoCall: Boolean) {
- val usersCount = usersAdapter!!.selectedUsers.size
- if (usersCount > MAX_OPPONENTS_COUNT) {
+ val usersCount = usersAdapter?.selectedUsers?.size
+ if (usersCount != null && usersCount > MAX_OPPONENTS_COUNT) {
longToast(String.format(getString(R.string.error_max_opponents_count), MAX_OPPONENTS_COUNT))
return
}
- val opponentsList = getIdsSelectedOpponents(usersAdapter!!.selectedUsers)
+ val userIds = usersAdapter?.selectedUsers?.let { getOpponentIds(it) }
val conferenceType = if (isVideoCall) {
QBRTCTypes.QBConferenceType.QB_CONFERENCE_TYPE_VIDEO
} else {
QBRTCTypes.QBConferenceType.QB_CONFERENCE_TYPE_AUDIO
}
- val qbrtcClient = QBRTCClient.getInstance(applicationContext)
- val newQbRtcSession = qbrtcClient.createNewSessionWithOpponents(opponentsList, conferenceType)
- WebRtcSessionManager.setCurrentSession(newQbRtcSession)
+ val rtcClient = QBRTCClient.getInstance(applicationContext)
+ val session = rtcClient.createNewSessionWithOpponents(userIds, conferenceType)
+ WebRtcSessionManager.setCurrentSession(session)
- // Make Users FullName Strings and ID's list for iOS VOIP push
- val newSessionID = newQbRtcSession.sessionID
- val opponentsIDsList = java.util.ArrayList()
- val opponentsNamesList = java.util.ArrayList()
- val usersInCall: ArrayList = usersAdapter!!.selectedUsers as ArrayList
+ // make Users FullName Strings and id's list for iOS VOIP push
+ val sessionId = session.sessionID
+ val opponentIds = ArrayList()
+ val opponentNames = ArrayList()
+ val usersInCall = usersAdapter?.selectedUsers as ArrayList
// the Caller in exactly first position is needed regarding to iOS 13 functionality
usersInCall.add(0, currentUser)
for (user in usersInCall) {
- val userId = user.id!!.toString()
- var userName = ""
- if (TextUtils.isEmpty(user.fullName)) {
- userName = user.login
- } else {
- userName = user.fullName
- }
+ val userId = user.id.toString()
+ val name = user.fullName ?: user.login
- opponentsIDsList.add(userId)
- opponentsNamesList.add(userName)
+ opponentIds.add(userId)
+ opponentNames.add(name)
}
- val opponentsIDsString = TextUtils.join(",", opponentsIDsList)
- val opponentNamesString = TextUtils.join(",", opponentsNamesList)
+ val idsInLine = TextUtils.join(",", opponentIds)
+ val namesInLine = TextUtils.join(",", opponentNames)
- Log.d(TAG, "New Session with ID: $newSessionID\n Users in Call: \n$opponentsIDsString\n$opponentNamesString")
- sendPushMessage(opponentsList, currentUser.fullName, newSessionID, opponentsIDsString, opponentNamesString, isVideoCall)
+ Log.d(TAG, "New Session with id: $sessionId\n Users in Call: \n$idsInLine\n$namesInLine")
+
+ userIds?.forEach { userId ->
+ Executor.addTask(object : ExecutorTask {
+ override fun onBackground(): Boolean {
+ val timeout3Seconds = 3000L
+ return QBChatService.getInstance().pingManager.pingUser(userId, timeout3Seconds)
+ }
+
+ override fun onForeground(result: Boolean) {
+ if (result) {
+ val message =
+ "Participant with id: $userId is online. There is no need to send a VoIP notification."
+ Log.d(TAG, message)
+ } else {
+ sendPushMessage(userId, currentUser.fullName, sessionId, idsInLine, namesInLine, isVideoCall)
+ }
+ }
+
+ override fun onError(exception: Exception) {
+ shortToast(exception.message.toString())
+ }
+ })
+ }
CallActivity.start(this, false)
}
- private fun getIdsSelectedOpponents(selectedUsers: Collection): ArrayList {
- val opponentsIds = ArrayList()
- if (!selectedUsers.isEmpty()) {
- for (qbUser in selectedUsers) {
- opponentsIds.add(qbUser.id)
- }
+ private fun getOpponentIds(opponents: Collection): ArrayList {
+ val opponentIds = ArrayList()
+ for (qbUser in opponents) {
+ opponentIds.add(qbUser.id)
}
- return opponentsIds
+ return opponentIds
}
private fun updateActionBar(countSelectedUsers: Int) {
@@ -306,49 +320,44 @@ class OpponentsActivity : BaseActivity() {
}
private fun initDefaultActionBar() {
- val currentUserFullName = SharedPrefsHelper.getQbUser().fullName
+ val currentUserFullName = SharedPrefsHelper.getCurrentUser().fullName
supportActionBar?.title = ""
supportActionBar?.subtitle = getString(R.string.subtitle_text_logged_in_as, currentUserFullName)
}
private fun logout() {
Log.d(TAG, "Removing User data, and Logout")
- LoginService.logout(this)
- QBUsers.signOut().performAsync(object : QBEntityCallback{
+ LoginService.logoutFromChat(this)
+ LoginService.destroyRTCClient(this)
+ QBUsers.signOut().performAsync(object : QBEntityCallback {
override fun onSuccess(v: Void?, b: Bundle?) {
removeAllUserData()
startLoginActivity()
}
- override fun onError(e: QBResponseException?) {
- showErrorSnackbar(R.string.dlg_error, e as Exception, object : View.OnClickListener{
- override fun onClick(v: View?) {
+ override fun onError(e: QBResponseException) {
+ showErrorSnackbar(R.string.dlg_error, e) {
+ unsubscribeFromPushes {
logout()
}
- })
+ }
}
})
}
- private fun unsubscribeFromPushesAndLogout() {
+ private fun unsubscribeFromPushes(callback: () -> Unit) {
if (QBPushManager.getInstance().isSubscribedToPushes) {
- QBPushManager.getInstance().addListener(object : QBPushSubscribeListenerImpl(){
- override fun onSubscriptionDeleted(success: Boolean) {
- Log.d(TAG, "Subscription Deleted")
- QBPushManager.getInstance().removeListener(this)
- logout()
- }
- })
+ QBPushManager.getInstance().addListener(SubscribeListener(TAG, callback))
SubscribeService.unSubscribeFromPushes(this@OpponentsActivity)
} else {
- logout()
+ callback()
}
}
private fun removeAllUserData() {
SharedPrefsHelper.clearAllData()
QbUsersDbManager.clearDB()
- signOut()
+ QBUsers.signOut().performAsync(null)
}
private fun startLoginActivity() {
@@ -357,7 +366,6 @@ class OpponentsActivity : BaseActivity() {
}
private inner class ScrollListener(val layoutManager: LinearLayoutManager) : RecyclerView.OnScrollListener() {
-
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
if (!isLoading && hasNextPage && dy > 0) {
val visibleItemCount = layoutManager.childCount
@@ -372,17 +380,32 @@ class OpponentsActivity : BaseActivity() {
}
}
- private open inner class QBPushSubscribeListenerImpl : QBPushManager.QBSubscribeListener {
- override fun onSubscriptionCreated() {
-
+ private inner class SubscribeListener(val tag: String?, val callback: () -> Unit) :
+ QBPushManager.QBSubscribeListener {
+ override fun onSubscriptionDeleted(success: Boolean) {
+ QBPushManager.getInstance().removeListener(this)
+ callback()
}
- override fun onSubscriptionError(e: Exception?, i: Int) {
+ override fun onSubscriptionCreated() {
+ // empty
+ }
+ override fun onSubscriptionError(p0: Exception?, p1: Int) {
+ // empty
}
- override fun onSubscriptionDeleted(b: Boolean) {
+ override fun equals(other: Any?): Boolean {
+ if (other is SubscribeListener) {
+ return tag == other.tag
+ }
+ return false
+ }
+ override fun hashCode(): Int {
+ var hash = 1
+ hash = 31 * hash + tag.hashCode()
+ return hash
}
}
}
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/SettingsActivity.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/SettingsActivity.kt
deleted file mode 100644
index 0b502ade2..000000000
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/SettingsActivity.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.quickblox.sample.videochat.kotlin.activities
-
-import android.content.Context
-import android.content.Intent
-import android.content.SharedPreferences
-import android.os.Bundle
-import android.preference.EditTextPreference
-import com.quickblox.sample.videochat.kotlin.R
-import com.quickblox.sample.videochat.kotlin.fragments.SettingsFragment
-import com.quickblox.sample.videochat.kotlin.utils.longToast
-import com.quickblox.sample.videochat.kotlin.view.SeekBarPreference
-
-private const val MAX_VIDEO_START_BITRATE = 2000
-
-class SettingsActivity : BaseActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
-
- private lateinit var bitrateStringKey: String
- private lateinit var settingsFragment: SettingsFragment
-
- companion object {
- fun start(context: Context) = context.startActivity(Intent(context, SettingsActivity::class.java))
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- supportActionBar?.title = getString(R.string.actionbar_title_settings)
-
- // Display the fragment as the main content.
- settingsFragment = SettingsFragment()
- fragmentManager.beginTransaction()
- .replace(android.R.id.content, settingsFragment)
- .commit()
- bitrateStringKey = getString(R.string.pref_startbitratevalue_key)
- }
-
- override fun onResume() {
- super.onResume()
- val sharedPreferences = settingsFragment.preferenceScreen.sharedPreferences
- sharedPreferences.registerOnSharedPreferenceChangeListener(this)
- }
-
- override fun onPause() {
- super.onPause()
- val sharedPreferences = settingsFragment.preferenceScreen.sharedPreferences
- sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
- }
-
- override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
- if (key == bitrateStringKey) {
- val bitrateValue = sharedPreferences?.getInt(bitrateStringKey, Integer.parseInt(getString(R.string.pref_startbitratevalue_default)))!!
- if (bitrateValue == 0) {
- setDefaultstartingBitrate(sharedPreferences)
- return
- }
- if (bitrateValue > MAX_VIDEO_START_BITRATE) {
- longToast("Max value is:$MAX_VIDEO_START_BITRATE")
- setDefaultstartingBitrate(sharedPreferences)
- }
- }
- }
-
- private fun setDefaultstartingBitrate(sharedPreferences: SharedPreferences) {
- val editor = sharedPreferences.edit()
- editor.putInt(bitrateStringKey,
- Integer.parseInt(getString(R.string.pref_startbitratevalue_default)))
- editor.apply()
- updateSummary(sharedPreferences, bitrateStringKey)
- }
-
- private fun updateSummary(sharedPreferences: SharedPreferences, key: String) {
- val updatedPref = settingsFragment.findPreference(key)
- // Set summary to be the user-description for the selected value
- if (updatedPref is EditTextPreference) {
- updatedPref.text = sharedPreferences.getString(key, "")
- } else if (updatedPref is SeekBarPreference) {
- updatedPref.setSummary(sharedPreferences.getInt(key, 0).toString())
- } else {
- updatedPref?.summary = sharedPreferences.getString(key, "")
- }
- }
-}
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/SplashActivity.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/SplashActivity.kt
index 8d45c239e..1388034fd 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/SplashActivity.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/SplashActivity.kt
@@ -1,6 +1,5 @@
package com.quickblox.sample.videochat.kotlin.activities
-import android.content.DialogInterface
import android.content.Intent
import android.net.Uri
import android.os.Build
@@ -38,8 +37,8 @@ class SplashActivity : BaseActivity() {
}
private fun runNextScreen() {
- if (SharedPrefsHelper.hasQbUser()) {
- LoginService.start(this, SharedPrefsHelper.getQbUser())
+ if (SharedPrefsHelper.hasCurrentUser()) {
+ LoginService.loginToChatAndInitRTCClient(this, SharedPrefsHelper.getCurrentUser())
OpponentsActivity.start(this)
} else {
Handler().postDelayed({
@@ -80,7 +79,7 @@ class SplashActivity : BaseActivity() {
return false
} else if (isMiUi() && !miOverlayChecked) {
Log.e(TAG, "Xiaomi Device. Need additional Overlay Permissions")
- buildMIUIOverlayPermissionAlertDialog()
+ showMIUIOverlayPermissionDialog()
return false
}
}
@@ -123,7 +122,7 @@ class SplashActivity : BaseActivity() {
}
}
- fun buildMIUIOverlayPermissionAlertDialog() {
+ private fun showMIUIOverlayPermissionDialog() {
val builder = AlertDialog.Builder(this)
builder.setTitle("Additional Overlay Permission Required")
builder.setIcon(R.drawable.ic_error_outline_orange_24dp)
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/adapters/OpponentsFromCallAdapter.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/adapters/OpponentsFromCallAdapter.kt
index bcddd30d0..c721b10f8 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/adapters/OpponentsFromCallAdapter.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/adapters/OpponentsFromCallAdapter.kt
@@ -18,12 +18,11 @@ import com.quickblox.users.model.QBUser
import com.quickblox.videochat.webrtc.QBRTCTypes
import com.quickblox.videochat.webrtc.view.QBRTCSurfaceView
-
class OpponentsFromCallAdapter(val context: Context,
- val baseConversationFragment: BaseConversationFragment,
- val users: List,
- val width: Int,
- val height: Int) : RecyclerView.Adapter() {
+ private val baseConversationFragment: BaseConversationFragment,
+ users: List,
+ private val width: Int,
+ private val height: Int) : RecyclerView.Adapter() {
private val TAG = OpponentsFromCallAdapter::class.java.simpleName
@@ -75,7 +74,8 @@ class OpponentsFromCallAdapter(val context: Context,
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val user = _opponents[position]
val userID = user.id
- holder.opponentsName.text = user.fullName
+ val name = user.fullName ?: user.login
+ holder.opponentsName.text = name
holder.getOpponentView().id = user.id
holder.setUserId(userID)
@@ -103,10 +103,10 @@ class OpponentsFromCallAdapter(val context: Context,
init {
itemView.setOnClickListener(this)
- opponentsName = itemView.findViewById(R.id.opponent_name) as TextView
- connectionStatus = itemView.findViewById(R.id.connection_status) as TextView
- opponentView = itemView.findViewById(R.id.opponent_view) as QBRTCSurfaceView
- progressBar = itemView.findViewById(R.id.progress_bar_adapter) as ProgressBar
+ opponentsName = itemView.findViewById(R.id.opponent_name)
+ connectionStatus = itemView.findViewById(R.id.connection_status)
+ opponentView = itemView.findViewById(R.id.opponent_view)
+ progressBar = itemView.findViewById(R.id.progress_bar_adapter)
}
fun setListener(viewHolderClickListener: ViewHolderClickListener) {
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/adapters/UsersAdapter.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/adapters/UsersAdapter.kt
index 4f3742c25..ed53827a5 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/adapters/UsersAdapter.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/adapters/UsersAdapter.kt
@@ -12,25 +12,22 @@ import com.quickblox.sample.videochat.kotlin.utils.getColoredCircleDrawable
import com.quickblox.users.model.QBUser
import kotlinx.android.synthetic.main.item_opponents_list.view.*
+class UsersAdapter(private val context: Context, private var usersList: ArrayList) :
+ RecyclerView.Adapter() {
-class UsersAdapter : RecyclerView.Adapter {
-
- val context: Context
- private var usersList: ArrayList
private val _selectedUsers: MutableList
val selectedUsers: List
get() = _selectedUsers
private lateinit var selectedItemsCountsChangedListener: SelectedItemsCountsChangedListener
- constructor(context: Context, usersList: ArrayList) : super() {
- this.context = context
- this.usersList = usersList
+ init {
this._selectedUsers = ArrayList()
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val user = usersList[position]
- holder.opponentName.text = user.fullName
+ val name = user.fullName ?: user.login
+ holder.opponentName.text = name
if (_selectedUsers.contains(user)) {
holder.rootLayout.setBackgroundResource(R.color.background_color_selected_user_item)
holder.opponentIcon.setBackgroundDrawable(
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/executor/Executor.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/executor/Executor.kt
new file mode 100644
index 000000000..ca0942fef
--- /dev/null
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/executor/Executor.kt
@@ -0,0 +1,44 @@
+package com.quickblox.sample.videochat.kotlin.executor
+
+import android.os.Handler
+import android.os.Looper
+import java.util.concurrent.BlockingQueue
+import java.util.concurrent.LinkedBlockingQueue
+import java.util.concurrent.ThreadPoolExecutor
+import java.util.concurrent.TimeUnit
+
+private const val THREAD_POOL_SIZE = 3
+private const val MAX_POOL_SIZE = 3
+private const val KEEP_ALIVE_TIME = 1L
+
+object Executor {
+ private var threadPoolExecutor: ThreadPoolExecutor? = null
+ private val threadQueue: BlockingQueue = LinkedBlockingQueue()
+
+ init {
+ threadPoolExecutor = ThreadPoolExecutor(
+ THREAD_POOL_SIZE,
+ MAX_POOL_SIZE,
+ KEEP_ALIVE_TIME,
+ TimeUnit.SECONDS,
+ threadQueue
+ )
+ }
+
+ fun addTask(executorTask: ExecutorTask) {
+ threadPoolExecutor?.execute {
+ val mainHandler = Handler(Looper.getMainLooper())
+
+ try {
+ val result = executorTask.onBackground()
+ mainHandler.post {
+ executorTask.onForeground(result)
+ }
+ } catch (exception: Exception) {
+ mainHandler.post {
+ executorTask.onError(exception)
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/executor/ExecutorCallback.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/executor/ExecutorCallback.kt
new file mode 100644
index 000000000..7883f70dd
--- /dev/null
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/executor/ExecutorCallback.kt
@@ -0,0 +1,10 @@
+package com.quickblox.sample.videochat.kotlin.executor
+
+interface ExecutorTask {
+ @Throws(Exception::class)
+ fun onBackground(): T
+
+ fun onForeground(result: T)
+
+ fun onError(exception: Exception)
+}
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/AudioConversationFragment.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/AudioConversationFragment.kt
index fb9b653f1..809773578 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/AudioConversationFragment.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/AudioConversationFragment.kt
@@ -18,6 +18,7 @@ import java.util.*
const val SPEAKER_ENABLED = "is_speaker_enabled"
class AudioConversationFragment : BaseConversationFragment(), CallActivity.OnChangeAudioDevice {
+ private val TAG = AudioConversationFragment::class.simpleName
private lateinit var audioSwitchToggleButton: ToggleButton
private lateinit var alsoOnCallText: TextView
@@ -29,6 +30,18 @@ class AudioConversationFragment : BaseConversationFragment(), CallActivity.OnCha
conversationFragmentCallback?.addOnChangeAudioDeviceListener(this)
}
+ override fun onResume() {
+ super.onResume()
+ conversationFragmentCallback?.addCallTimeUpdateListener(CallTimeUpdateListenerImpl(TAG))
+ conversationFragmentCallback?.addUpdateOpponentsListener(UpdateOpponentsListenerImpl(TAG))
+ }
+
+ override fun onPause() {
+ super.onPause()
+ conversationFragmentCallback?.removeCallTimeUpdateListener(CallTimeUpdateListenerImpl(TAG))
+ conversationFragmentCallback?.removeUpdateOpponentsListener(UpdateOpponentsListenerImpl(TAG))
+ }
+
override fun configureOutgoingScreen() {
val context: Context = activity as Context
outgoingOpponentsRelativeLayout.setBackgroundColor(ContextCompat.getColor(context, R.color.white))
@@ -37,11 +50,10 @@ class AudioConversationFragment : BaseConversationFragment(), CallActivity.OnCha
}
override fun configureToolbar() {
- val context: Context = activity as Context
- toolbar.visibility = View.VISIBLE
- toolbar.setBackgroundColor(ContextCompat.getColor(context, R.color.white))
- toolbar.setTitleTextColor(ContextCompat.getColor(context, R.color.toolbar_title_color))
- toolbar.setSubtitleTextColor(ContextCompat.getColor(context, R.color.toolbar_subtitle_color))
+ toolbar?.visibility = View.VISIBLE
+ toolbar?.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white))
+ toolbar?.setTitleTextColor(ContextCompat.getColor(requireContext(), R.color.toolbar_title_color))
+ toolbar?.setSubtitleTextColor(ContextCompat.getColor(requireContext(), R.color.toolbar_subtitle_color))
}
override fun configureActionBar() {
@@ -62,18 +74,19 @@ class AudioConversationFragment : BaseConversationFragment(), CallActivity.OnCha
setVisibilityAlsoOnCallTextView()
firstOpponentNameTextView = view.findViewById(R.id.text_caller_name)
- firstOpponentNameTextView.text = opponents[0].fullName
+ val name = opponents[0].fullName ?: opponents[0].login
+ firstOpponentNameTextView.text =name
- otherOpponentsTextView = view.findViewById(R.id.text_other_inc_users)
- otherOpponentsTextView.text = getOtherOpponentsNames()
+ otherOpponentsTextView = view.findViewById(R.id.text_other_users)
+ otherOpponentsTextView.text = getOtherOpponentNames()
audioSwitchToggleButton = view.findViewById(R.id.toggle_speaker)
audioSwitchToggleButton.visibility = View.VISIBLE
audioSwitchToggleButton.isChecked = SharedPrefsHelper.get(SPEAKER_ENABLED, true)
actionButtonsEnabled(false)
- if (conversationFragmentCallback?.isCallState() == true) {
- onCallStarted()
+ if (conversationFragmentCallback?.isConnectedCall() == true) {
+ startedCall()
}
}
@@ -83,7 +96,7 @@ class AudioConversationFragment : BaseConversationFragment(), CallActivity.OnCha
}
}
- private fun getOtherOpponentsNames(): String {
+ private fun getOtherOpponentNames(): String {
val otherOpponents = ArrayList()
otherOpponents.addAll(opponents)
otherOpponents.removeAt(0)
@@ -124,17 +137,47 @@ class AudioConversationFragment : BaseConversationFragment(), CallActivity.OnCha
return R.layout.fragment_audio_conversation
}
- override fun onOpponentsListUpdated(newUsers: ArrayList) {
- super.onOpponentsListUpdated(newUsers)
- firstOpponentNameTextView.text = opponents[0].fullName
- otherOpponentsTextView.text = getOtherOpponentsNames()
+ override fun audioDeviceChanged(newAudioDevice: AppRTCAudioManager.AudioDevice) {
+ audioSwitchToggleButton.isChecked = newAudioDevice != AppRTCAudioManager.AudioDevice.SPEAKER_PHONE
}
- override fun onCallTimeUpdate(time: String) {
- timerCallText.text = time
+ private inner class UpdateOpponentsListenerImpl(val tag: String?) : CallActivity.UpdateOpponentsListener {
+ override fun updatedOpponents(updatedOpponents: ArrayList) {
+ val name = opponents[0].fullName ?: opponents[0].login
+ firstOpponentNameTextView.text = name
+ otherOpponentsTextView.text = getOtherOpponentNames()
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (other is UpdateOpponentsListenerImpl) {
+ return tag == other.tag
+ }
+ return false
+ }
+
+ override fun hashCode(): Int {
+ var hash = 1
+ hash = 31 * hash + tag.hashCode()
+ return hash
+ }
}
- override fun audioDeviceChanged(newAudioDevice: AppRTCAudioManager.AudioDevice) {
- audioSwitchToggleButton.isChecked = newAudioDevice != AppRTCAudioManager.AudioDevice.SPEAKER_PHONE
+ private inner class CallTimeUpdateListenerImpl(val tag: String?) : CallActivity.CallTimeUpdateListener {
+ override fun updatedCallTime(time: String) {
+ timerCallText.text = time
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (other is CallTimeUpdateListenerImpl) {
+ return tag == other.tag
+ }
+ return false
+ }
+
+ override fun hashCode(): Int {
+ var hash = 1
+ hash = 31 * hash + tag.hashCode()
+ return hash
+ }
}
}
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/BaseConversationFragment.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/BaseConversationFragment.kt
index 9707db697..144ea342f 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/BaseConversationFragment.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/BaseConversationFragment.kt
@@ -10,6 +10,7 @@ import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.TextView
import android.widget.ToggleButton
+import androidx.collection.arrayMapOf
import com.quickblox.chat.QBChatService
import com.quickblox.core.helper.StringifyArrayList
import com.quickblox.sample.videochat.kotlin.R
@@ -26,8 +27,8 @@ import kotlin.collections.HashMap
private val TAG = BaseConversationFragment::class.java.simpleName
const val MIC_ENABLED = "is_microphone_enabled"
-abstract class BaseConversationFragment : BaseToolBarFragment(), CallActivity.CurrentCallStateCallback {
-
+abstract class BaseConversationFragment : BaseToolBarFragment() {
+ private val TAG = BaseConversationFragment::class.simpleName
private var isIncomingCall: Boolean = false
protected lateinit var timerCallText: TextView
protected var conversationFragmentCallback: ConversationFragmentCallback? = null
@@ -40,6 +41,7 @@ abstract class BaseConversationFragment : BaseToolBarFragment(), CallActivity.Cu
protected lateinit var outgoingOpponentsRelativeLayout: View
protected lateinit var allOpponentsTextView: TextView
protected lateinit var ringingTextView: TextView
+ private val callStateListener = CallStateListenerImpl(TAG)
companion object {
fun newInstance(baseConversationFragment: BaseConversationFragment, isIncomingCall: Boolean): BaseConversationFragment {
@@ -62,7 +64,8 @@ abstract class BaseConversationFragment : BaseToolBarFragment(), CallActivity.Cu
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- conversationFragmentCallback?.addCurrentCallStateListener(this)
+ conversationFragmentCallback?.addCallStateListener(callStateListener)
+ conversationFragmentCallback?.addUpdateOpponentsListener(UpdateOpponentsListenerImpl(TAG))
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@@ -88,26 +91,26 @@ abstract class BaseConversationFragment : BaseToolBarFragment(), CallActivity.Cu
private fun prepareAndShowOutgoingScreen() {
configureOutgoingScreen()
- allOpponentsTextView.text = getUserNamesFromUsersFullNames(opponents)
+ allOpponentsTextView.text = getNamesFromOpponents(opponents)
}
- private fun getUserNamesFromUsersFullNames(allUsers: ArrayList): String {
- val usersNames = StringifyArrayList()
- for (user in allUsers) {
- if (user.fullName != null) {
- usersNames.add(user.fullName)
- } else if (user.id != null) {
- usersNames.add(user.id.toString())
+ private fun getNamesFromOpponents(allOpponents: ArrayList): String {
+ val opponentNames = StringifyArrayList()
+ for (opponent in allOpponents) {
+ if (opponent.fullName != null) {
+ opponentNames.add(opponent.fullName)
+ } else if (opponent.id != null) {
+ opponentNames.add(opponent.id.toString())
}
}
- return usersNames.itemsAsString.replace(",", ", ")
+ return opponentNames.itemsAsString.replace(",", ", ")
}
protected abstract fun configureOutgoingScreen()
protected open fun initFields() {
if (QBChatService.getInstance().user == null) {
- currentUser = SharedPrefsHelper.getQbUser()
+ currentUser = SharedPrefsHelper.getCurrentUser()
} else {
currentUser = QBChatService.getInstance().user
}
@@ -115,7 +118,7 @@ abstract class BaseConversationFragment : BaseToolBarFragment(), CallActivity.Cu
arguments?.let {
isIncomingCall = it.getBoolean(EXTRA_IS_INCOMING_CALL, false)
}
- initOpponentsList()
+ initOpponents()
Log.d(TAG, "opponents: $opponents")
}
@@ -124,22 +127,27 @@ abstract class BaseConversationFragment : BaseToolBarFragment(), CallActivity.Cu
if (isIncomingCall) {
conversationFragmentCallback?.acceptCall(HashMap())
} else {
- conversationFragmentCallback?.startCall(HashMap())
+ val userInfo = arrayMapOf()
+ userInfo["timestamp"] = System.currentTimeMillis().toString()
+ conversationFragmentCallback?.startCall(userInfo)
}
}
override fun onDestroy() {
- conversationFragmentCallback?.removeCurrentCallStateListener(this)
+ conversationFragmentCallback?.removeCallStateListener(callStateListener)
+ conversationFragmentCallback?.removeUpdateOpponentsListener(UpdateOpponentsListenerImpl(TAG))
super.onDestroy()
}
protected open fun initViews(view: View?) {
- micToggleVideoCall = view?.findViewById(R.id.toggle_mic) as ToggleButton
- micToggleVideoCall.isChecked = SharedPrefsHelper.get(MIC_ENABLED, true)
- handUpVideoCall = view.findViewById(R.id.button_hangup_call) as ImageButton
- outgoingOpponentsRelativeLayout = view.findViewById(R.id.layout_background_outgoing_screen)
- allOpponentsTextView = view.findViewById(R.id.text_outgoing_opponents_names) as TextView
- ringingTextView = view.findViewById(R.id.text_ringing) as TextView
+ view?.let {
+ micToggleVideoCall = it.findViewById(R.id.toggle_mic)
+ micToggleVideoCall.isChecked = SharedPrefsHelper[MIC_ENABLED, true]
+ handUpVideoCall = it.findViewById(R.id.button_hangup_call)
+ outgoingOpponentsRelativeLayout = it.findViewById(R.id.layout_background_outgoing_screen)
+ allOpponentsTextView = it.findViewById(R.id.text_outgoing_opponents_names)
+ ringingTextView = it.findViewById(R.id.text_ringing)
+ }
if (isIncomingCall) {
hideOutgoingScreen()
@@ -170,7 +178,6 @@ abstract class BaseConversationFragment : BaseToolBarFragment(), CallActivity.Cu
protected open fun actionButtonsEnabled(inability: Boolean) {
micToggleVideoCall.isEnabled = inability
- // inactivate toggle buttons
micToggleVideoCall.isActivated = inability
}
@@ -185,43 +192,26 @@ abstract class BaseConversationFragment : BaseToolBarFragment(), CallActivity.Cu
outgoingOpponentsRelativeLayout.visibility = View.GONE
}
- override fun onCallStarted() {
- hideOutgoingScreen()
- startTimer()
- actionButtonsEnabled(true)
- }
-
- override fun onCallStopped() {
- isStarted = false
- clearButtonsState()
- actionButtonsEnabled(false)
- }
-
- override fun onOpponentsListUpdated(newUsers: ArrayList) {
- initOpponentsList()
- }
-
- private fun initOpponentsList() {
- Log.v("UPDATE_USERS", "super initOpponentsList()")
- val opponnentsIds = conversationFragmentCallback?.getOpponents()
- opponnentsIds?.let {
+ private fun initOpponents() {
+ val opponentIds = conversationFragmentCallback?.getOpponents()
+ opponentIds?.let {
val usersFromDb = QbUsersDbManager.getUsersByIds(it)
- opponents = getListAllUsersFromIds(usersFromDb, it)
- }
-
- var caller = QbUsersDbManager.getUserById(conversationFragmentCallback?.getCallerId())
- if (caller == null) {
- caller = QBUser(conversationFragmentCallback?.getCallerId())
- caller.fullName = conversationFragmentCallback?.getCallerId().toString()
+ opponents = checkAndModifyOpponents(usersFromDb, it)
}
if (isIncomingCall) {
+ var caller = QbUsersDbManager.getUserById(conversationFragmentCallback?.getCallerId())
+ if (caller == null) {
+ caller = QBUser(conversationFragmentCallback?.getCallerId())
+ caller.fullName = conversationFragmentCallback?.getCallerId().toString()
+ }
+
opponents.add(caller)
opponents.remove(QBChatService.getInstance().user)
}
}
- private fun getListAllUsersFromIds(existedUsers: ArrayList, allIds: List): ArrayList {
+ private fun checkAndModifyOpponents(existedUsers: ArrayList, allIds: List): ArrayList {
val qbUsers = ArrayList()
for (userId in allIds) {
val stubUser = createStubUserById(userId)
@@ -242,4 +232,55 @@ abstract class BaseConversationFragment : BaseToolBarFragment(), CallActivity.Cu
fun getConnectionState(userId: Int): QBRTCTypes.QBRTCConnectionState? {
return conversationFragmentCallback?.getPeerChannel(userId)
}
+
+ protected fun startedCall() {
+ callStateListener.startedCall()
+ }
+
+ private inner class CallStateListenerImpl(val tag: String?) : CallActivity.CallStateListener {
+ override fun startedCall() {
+ hideOutgoingScreen()
+ startTimer()
+ actionButtonsEnabled(true)
+ }
+
+ override fun stoppedCall() {
+ isStarted = false
+ clearButtonsState()
+ actionButtonsEnabled(false)
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (other is CallStateListenerImpl) {
+ return tag == other.tag
+ }
+ return false
+ }
+
+ override fun hashCode(): Int {
+ var hash = 1
+ hash = 31 * hash + tag.hashCode()
+ return hash
+ }
+ }
+
+ private inner class UpdateOpponentsListenerImpl(val tag: String?) : CallActivity.UpdateOpponentsListener {
+ override fun updatedOpponents(updatedOpponents: ArrayList) {
+ initOpponents()
+ allOpponentsTextView.text = getNamesFromOpponents(opponents)
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (other is UpdateOpponentsListenerImpl) {
+ return tag == other.tag
+ }
+ return false
+ }
+
+ override fun hashCode(): Int {
+ var hash = 1
+ hash = 31 * hash + tag.hashCode()
+ return hash
+ }
+ }
}
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/BaseToolBarFragment.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/BaseToolBarFragment.kt
index 83954fcdf..0f8663b5c 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/BaseToolBarFragment.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/BaseToolBarFragment.kt
@@ -13,23 +13,18 @@ import androidx.fragment.app.Fragment
import com.quickblox.sample.videochat.kotlin.R
import java.lang.ref.WeakReference
-
abstract class BaseToolBarFragment : Fragment() {
-
protected lateinit var actionBar: ActionBar
- protected lateinit var toolbar: Toolbar
-
- protected var mainHandler: Handler
+ protected var toolbar: Toolbar? = null
- init {
- mainHandler = FragmentLifeCycleHandler(this)
- }
+ protected var mainHandler: Handler? = null
internal abstract fun getFragmentLayout(): Int
override fun onCreate(savedInstanceState: Bundle?) {
setHasOptionsMenu(true)
super.onCreate(savedInstanceState)
+ mainHandler = FragmentLifeCycleHandler(this)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@@ -39,7 +34,7 @@ abstract class BaseToolBarFragment : Fragment() {
}
private fun initActionBar() {
- toolbar = activity?.findViewById(R.id.toolbar_call) as Toolbar
+ toolbar = activity?.findViewById(R.id.toolbar_call)
(activity as AppCompatActivity).setSupportActionBar(toolbar)
actionBar = (activity as AppCompatActivity).delegate.supportActionBar as ActionBar
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/ConversationFragmentCallback.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/ConversationFragmentCallback.kt
index e8cd55dda..65fb0ab00 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/ConversationFragmentCallback.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/ConversationFragmentCallback.kt
@@ -11,7 +11,6 @@ import com.quickblox.videochat.webrtc.view.QBRTCVideoTrack
import org.jivesoftware.smack.ConnectionListener
import org.webrtc.CameraVideoCapturer
-
interface ConversationFragmentCallback {
fun addConnectionListener(connectionCallback: ConnectionListener?)
@@ -30,9 +29,17 @@ interface ConversationFragmentCallback {
fun removeSessionEventsListener(eventsCallback: QBRTCSessionEventsCallback?)
- fun addCurrentCallStateListener(currentCallStateCallback: CallActivity.CurrentCallStateCallback?)
+ fun addCallStateListener(callStateListener: CallActivity.CallStateListener)
+
+ fun removeCallStateListener(callStateListener: CallActivity.CallStateListener)
+
+ fun addUpdateOpponentsListener(updateOpponentsListener: CallActivity.UpdateOpponentsListener)
+
+ fun removeUpdateOpponentsListener(updateOpponentsListener: CallActivity.UpdateOpponentsListener)
+
+ fun addCallTimeUpdateListener(callTimeUpdateListener: CallActivity.CallTimeUpdateListener)
- fun removeCurrentCallStateListener(currentCallStateCallback: CallActivity.CurrentCallStateCallback?)
+ fun removeCallTimeUpdateListener(callTimeUpdateListener: CallActivity.CallTimeUpdateListener)
fun addOnChangeAudioDeviceListener(onChangeDynamicCallback: CallActivity.OnChangeAudioDevice?)
@@ -66,7 +73,7 @@ interface ConversationFragmentCallback {
fun isMediaStreamManagerExist(): Boolean
- fun isCallState(): Boolean
+ fun isConnectedCall(): Boolean
fun getVideoTrackMap(): MutableMap
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/IncomeCallFragment.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/IncomeCallFragment.kt
index e12090bc9..33df13e9b 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/IncomeCallFragment.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/IncomeCallFragment.kt
@@ -1,6 +1,5 @@
package com.quickblox.sample.videochat.kotlin.fragments
-import android.app.Activity
import android.content.Context
import android.graphics.drawable.Drawable
import android.os.Bundle
@@ -15,6 +14,7 @@ import android.widget.ImageButton
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
+import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.Fragment
import com.quickblox.chat.QBChatService
import com.quickblox.core.QBEntityCallback
@@ -23,8 +23,8 @@ import com.quickblox.core.helper.StringifyArrayList
import com.quickblox.core.request.GenericQueryRule
import com.quickblox.core.request.QBPagedRequestBuilder
import com.quickblox.sample.videochat.kotlin.R
+import com.quickblox.sample.videochat.kotlin.activities.CallActivity
import com.quickblox.sample.videochat.kotlin.db.QbUsersDbManager
-import com.quickblox.sample.videochat.kotlin.util.loadUsersByPagedRequestBuilder
import com.quickblox.sample.videochat.kotlin.utils.RingtonePlayer
import com.quickblox.sample.videochat.kotlin.utils.WebRtcSessionManager
import com.quickblox.sample.videochat.kotlin.utils.getColorCircleDrawable
@@ -33,7 +33,6 @@ import com.quickblox.users.model.QBUser
import com.quickblox.videochat.webrtc.QBRTCSession
import com.quickblox.videochat.webrtc.QBRTCTypes
import java.io.Serializable
-import java.util.*
import java.util.concurrent.TimeUnit
private const val PER_PAGE_SIZE_100 = 100
@@ -51,13 +50,14 @@ class IncomeCallFragment : Fragment(), Serializable, View.OnClickListener {
private lateinit var alsoOnCallText: TextView
private lateinit var progressUserName: ProgressBar
private lateinit var callerNameTextView: TextView
-
- private var opponentsIds: List? = null
+ private var otherUsersTextView: TextView? = null
+ private var opponentIds: List? = null
private var vibrator: Vibrator? = null
private var conferenceType: QBRTCTypes.QBConferenceType? = null
private var lastClickTime = 0L
private lateinit var ringtonePlayer: RingtonePlayer
private lateinit var incomeCallFragmentCallbackListener: IncomeCallFragmentCallbackListener
+
private var currentSession: QBRTCSession? = null
override fun onAttach(context: Context) {
@@ -76,6 +76,16 @@ class IncomeCallFragment : Fragment(), Serializable, View.OnClickListener {
super.onCreate(savedInstanceState)
}
+ override fun onResume() {
+ super.onResume()
+ (requireActivity() as CallActivity).addUpdateOpponentsListener(UpdateOpponentsListenerImpl(TAG))
+ }
+
+ override fun onPause() {
+ super.onPause()
+ (requireActivity() as CallActivity).removeUpdateOpponentsListener(UpdateOpponentsListenerImpl(TAG))
+ }
+
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_income_call, container, false)
@@ -97,14 +107,14 @@ class IncomeCallFragment : Fragment(), Serializable, View.OnClickListener {
currentSession = WebRtcSessionManager.getCurrentSession()
currentSession?.let {
- opponentsIds = it.opponents
+ opponentIds = it.opponents
conferenceType = it.conferenceType
Log.d(TAG, conferenceType.toString() + "From onCreateView()")
}
}
private fun hideToolBar() {
- val toolbar = activity?.findViewById(R.id.toolbar_call)
+ val toolbar: Toolbar? = activity?.findViewById(R.id.toolbar_call)
toolbar?.visibility = View.GONE
}
@@ -120,9 +130,9 @@ class IncomeCallFragment : Fragment(), Serializable, View.OnClickListener {
private fun initUI(view: View) {
callTypeTextView = view.findViewById(R.id.call_type)
- val callerAvatarImageView = view.findViewById(R.id.image_caller_avatar)
+ val callerAvatarImageView: ImageView = view.findViewById(R.id.image_caller_avatar)
callerNameTextView = view.findViewById(R.id.text_caller_name)
- val otherIncUsersTextView = view.findViewById(R.id.text_other_inc_users)
+ otherUsersTextView = view.findViewById(R.id.text_other_users)
progressUserName = view.findViewById(R.id.progress_bar_opponent_name)
alsoOnCallText = view.findViewById(R.id.text_also_on_call)
rejectButton = view.findViewById(R.id.image_button_reject_call)
@@ -134,14 +144,15 @@ class IncomeCallFragment : Fragment(), Serializable, View.OnClickListener {
val callerUser = QbUsersDbManager.getUserById(currentSession?.callerID)
- if (callerUser != null && !TextUtils.isEmpty(callerUser.fullName)) {
- callerNameTextView.text = callerUser.fullName
+ if (callerUser != null) {
+ val name = callerUser.fullName ?: callerUser.login
+ callerNameTextView.text = name
} else {
callerNameTextView.text = currentSession?.callerID.toString()
updateUserFromServer()
}
- otherIncUsersTextView.text = getOtherIncUsersNames()
+ otherUsersTextView?.text = getOtherIncUsersNames()
setVisibilityAlsoOnCallTextView()
}
@@ -149,22 +160,23 @@ class IncomeCallFragment : Fragment(), Serializable, View.OnClickListener {
private fun updateUserFromServer() {
progressUserName.visibility = View.VISIBLE
- val callerID = currentSession?.callerID!!
- QBUsers.getUser(callerID).performAsync(object : QBEntityCallback {
- override fun onSuccess(qbUser: QBUser?, b: Bundle?) {
- if (qbUser != null) {
- QbUsersDbManager.saveUser(qbUser)
- val callerName = if (TextUtils.isEmpty(qbUser.fullName)) qbUser.login else qbUser.fullName
- callerNameTextView.text = callerName
+ currentSession?.let {
+ QBUsers.getUser(it.callerID).performAsync(object : QBEntityCallback {
+ override fun onSuccess(qbUser: QBUser?, bundle: Bundle?) {
+ if (qbUser != null) {
+ QbUsersDbManager.saveUser(qbUser)
+ val callerName = if (TextUtils.isEmpty(qbUser.fullName)) qbUser.login else qbUser.fullName
+ callerNameTextView.text = callerName
+ }
+ progressUserName.visibility = View.GONE
}
- progressUserName.visibility = View.GONE
- }
- override fun onError(e: QBResponseException?) {
- progressUserName.visibility = View.GONE
- e?.printStackTrace()
- }
- })
+ override fun onError(e: QBResponseException?) {
+ progressUserName.visibility = View.GONE
+ e?.printStackTrace()
+ }
+ })
+ }
val rules = ArrayList()
rules.add(GenericQueryRule(ORDER_RULE, ORDER_DESC_UPDATED))
@@ -172,12 +184,13 @@ class IncomeCallFragment : Fragment(), Serializable, View.OnClickListener {
requestBuilder.rules = rules
requestBuilder.perPage = PER_PAGE_SIZE_100
- loadUsersByPagedRequestBuilder(object : QBEntityCallback> {
+ QBUsers.getUsers(requestBuilder).performAsync(object : QBEntityCallback> {
override fun onSuccess(users: ArrayList, params: Bundle?) {
QbUsersDbManager.saveAllUsers(users, true)
- var callerUser: QBUser? = QbUsersDbManager.getUserById(currentSession?.callerID)
- if (callerUser != null && !TextUtils.isEmpty(callerUser.fullName)) {
- callerNameTextView.text = callerUser.fullName
+ val callerUser: QBUser? = QbUsersDbManager.getUserById(currentSession?.callerID)
+ if (callerUser != null) {
+ val name = callerUser.fullName ?: callerUser.login
+ callerNameTextView.text = name
}
progressUserName.visibility = View.GONE
}
@@ -185,11 +198,11 @@ class IncomeCallFragment : Fragment(), Serializable, View.OnClickListener {
override fun onError(e: QBResponseException?) {
progressUserName.visibility = View.GONE
}
- }, requestBuilder)
+ })
}
private fun setVisibilityAlsoOnCallTextView() {
- opponentsIds?.let {
+ opponentIds?.let {
if (it.size < 2) {
alsoOnCallText.visibility = View.INVISIBLE
}
@@ -222,13 +235,13 @@ class IncomeCallFragment : Fragment(), Serializable, View.OnClickListener {
private fun getOtherIncUsersNames(): String {
var result = ""
- opponentsIds?.let {
+ opponentIds?.let {
val usersFromDb = QbUsersDbManager.getUsersByIds(it)
val opponents = ArrayList()
- opponents.addAll(getListAllUsersFromIds(usersFromDb, it))
+ opponents.addAll(getAllUsersFromIds(usersFromDb, it))
opponents.remove(QBChatService.getInstance().user)
- Log.d(TAG, "opponentsIds = $opponentsIds")
+ Log.d(TAG, "opponentIds = $opponentIds")
result = makeStringFromUsersFullNames(opponents)
}
return result
@@ -247,7 +260,7 @@ class IncomeCallFragment : Fragment(), Serializable, View.OnClickListener {
return usersNames.itemsAsString.replace(",", ", ")
}
- fun getListAllUsersFromIds(existedUsers: ArrayList, allIds: List): ArrayList {
+ private fun getAllUsersFromIds(existedUsers: ArrayList, allIds: List): ArrayList {
val qbUsers = ArrayList()
for (userId in allIds) {
@@ -325,4 +338,23 @@ class IncomeCallFragment : Fragment(), Serializable, View.OnClickListener {
takeButton.isEnabled = enable
rejectButton.isEnabled = enable
}
+
+ private inner class UpdateOpponentsListenerImpl(val tag: String?) : CallActivity.UpdateOpponentsListener {
+ override fun updatedOpponents(updatedOpponents: ArrayList) {
+ otherUsersTextView?.text = getOtherIncUsersNames()
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (other is UpdateOpponentsListenerImpl) {
+ return tag == other.tag
+ }
+ return false
+ }
+
+ override fun hashCode(): Int {
+ var hash = 1
+ hash = 31 * hash + tag.hashCode()
+ return hash
+ }
+ }
}
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/PreviewFragment.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/PreviewFragment.kt
index 66d56f8ff..ef592f3e1 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/PreviewFragment.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/PreviewFragment.kt
@@ -26,7 +26,7 @@ class PreviewFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_item_screen_share, container, false)
- val ivPreview = view.findViewById(R.id.image_preview)
+ val ivPreview: ImageView = view.findViewById(R.id.image_preview)
val imageDrawable = arguments?.getInt(PREVIEW_IMAGE)
imageDrawable?.let {
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/ScreenShareFragment.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/ScreenShareFragment.kt
index dfa07de19..16863142d 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/ScreenShareFragment.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/ScreenShareFragment.kt
@@ -12,13 +12,10 @@ import androidx.fragment.app.FragmentPagerAdapter
import androidx.viewpager.widget.ViewPager
import com.quickblox.sample.videochat.kotlin.R
import com.quickblox.sample.videochat.kotlin.activities.CallActivity
-import com.quickblox.users.model.QBUser
-
class ScreenShareFragment : BaseToolBarFragment() {
private val TAG = ScreenShareFragment::class.simpleName
private var onSharingEvents: OnSharingEvents? = null
- private var currentCallStateCallback: CallActivity.CurrentCallStateCallback? = null
companion object {
fun newInstance(): ScreenShareFragment = ScreenShareFragment()
@@ -31,21 +28,20 @@ class ScreenShareFragment : BaseToolBarFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = super.onCreateView(inflater, container, savedInstanceState)
- val adapter = ImagesAdapter(childFragmentManager)
-
- val pager = view?.findViewById(R.id.pager) as ViewPager
- pager.adapter = adapter
+ view?.let {
+ val adapter = ImagesAdapter(childFragmentManager)
+ val pager: ViewPager = it.findViewById(R.id.pager)
+ pager.adapter = adapter
+ }
- val context = activity as Context
- toolbar.setBackgroundColor(ContextCompat.getColor(context, R.color.white))
+ toolbar?.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.white))
return view
}
override fun onResume() {
super.onResume()
- currentCallStateCallback = CurrentCallStateCallbackImpl()
- (activity as CallActivity).addCurrentCallStateListener(currentCallStateCallback!!)
+ (activity as CallActivity).addCallTimeUpdateListener(CallTimeUpdateListenerImpl(TAG))
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@@ -80,14 +76,13 @@ class ScreenShareFragment : BaseToolBarFragment() {
override fun onPause() {
super.onPause()
- currentCallStateCallback?.let {
- (activity as CallActivity).removeCurrentCallStateListener(it)
- }
+ (activity as CallActivity).removeCallTimeUpdateListener(CallTimeUpdateListenerImpl(TAG))
}
class ImagesAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) {
- private val images = intArrayOf(R.drawable.pres_img, R.drawable.p2p, R.drawable.group_call, R.drawable.opponents)
+ private val images =
+ intArrayOf(R.drawable.pres_img, R.drawable.p2p, R.drawable.group_call, R.drawable.opponents)
override fun getCount(): Int {
return images.size
@@ -98,23 +93,25 @@ class ScreenShareFragment : BaseToolBarFragment() {
}
}
- private inner class CurrentCallStateCallbackImpl : CallActivity.CurrentCallStateCallback {
- override fun onCallStarted() {
-
+ private inner class CallTimeUpdateListenerImpl(val tag: String?) : CallActivity.CallTimeUpdateListener {
+ override fun updatedCallTime(time: String) {
+ toolbar?.title = ""
+ val timerTextView: TextView? = toolbar?.findViewById(R.id.timer_call)
+ timerTextView?.visibility = View.VISIBLE
+ timerTextView?.text = time
}
- override fun onCallStopped() {
-
- }
-
- override fun onOpponentsListUpdated(newUsers: ArrayList) {
+ override fun equals(other: Any?): Boolean {
+ if (other is CallTimeUpdateListenerImpl) {
+ return tag == other.tag
+ }
+ return false
}
- override fun onCallTimeUpdate(time: String) {
- toolbar.title = ""
- val timerTextView = toolbar.findViewById(R.id.timer_call)
- timerTextView.visibility = View.VISIBLE
- timerTextView.text = time
+ override fun hashCode(): Int {
+ var hash = 1
+ hash = 31 * hash + tag.hashCode()
+ return hash
}
}
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/SettingsFragment.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/SettingsFragment.kt
deleted file mode 100644
index 5a8565c3b..000000000
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/SettingsFragment.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.quickblox.sample.videochat.kotlin.fragments
-
-import android.os.Bundle
-import android.preference.PreferenceFragment
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.ListView
-import com.quickblox.sample.videochat.kotlin.R
-
-
-class SettingsFragment : PreferenceFragment() {
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- addPreferencesFromResource(R.xml.preferences)
- }
-
- override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- val view = super.onCreateView(inflater, container, savedInstanceState)
- if (view != null) {
- val listView = view.findViewById(android.R.id.list) as ListView
- listView.setPadding(0, 0, 0, 0)
- }
- return view
- }
-}
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/VideoConversationFragment.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/VideoConversationFragment.kt
index f5514ac0b..9ffa4643b 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/VideoConversationFragment.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/fragments/VideoConversationFragment.kt
@@ -8,10 +8,7 @@ import android.os.SystemClock
import android.util.Log
import android.util.SparseArray
import android.view.*
-import android.widget.LinearLayout
-import android.widget.RelativeLayout
-import android.widget.TextView
-import android.widget.ToggleButton
+import android.widget.*
import androidx.annotation.DimenRes
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
@@ -53,11 +50,11 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
private lateinit var cameraToggle: ToggleButton
private var parentView: View? = null
private lateinit var actionVideoButtonsLayout: LinearLayout
- private lateinit var connectionStatusLocal: TextView
+ private lateinit var tvFullNameUser: TextView
private lateinit var recyclerView: RecyclerView
private var localVideoView: QBRTCSurfaceView? = null
+ private var containerLocalVideoView: FrameLayout? = null
private var remoteFullScreenVideoView: QBRTCSurfaceView? = null
-
private lateinit var opponentViewHolders: SparseArray
private lateinit var opponentsAdapter: OpponentsFromCallAdapter
private lateinit var allOpponents: MutableList
@@ -67,7 +64,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
private var optionsMenu: Menu? = null
private var isRemoteShown: Boolean = false
private var amountOpponents: Int = 0
- private var userIDFullScreen: Int = 0
+ private var userIdFullScreen: Int = 0
private var connectionEstablished: Boolean = false
private var allCallbacksInit: Boolean = false
private var isCurrentCameraFront: Boolean = false
@@ -98,6 +95,8 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
override fun onResume() {
super.onResume()
toggleCamera(cameraToggle.isChecked)
+ conversationFragmentCallback?.addUpdateOpponentsListener(UpdateOpponentsListenerImpl(TAG))
+ conversationFragmentCallback?.addCallTimeUpdateListener(CallTimeUpdateListenerImpl(TAG))
}
override fun onPause() {
@@ -128,6 +127,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
isRemoteShown = false
isCurrentCameraFront = true
localVideoView = view.findViewById(R.id.local_video_view)
+ containerLocalVideoView = view.findViewById(R.id.container_local_video_view)
initCorrectSizeForLocalView()
localVideoView?.setZOrderMediaOverlay(true)
@@ -137,8 +137,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
if (!isPeerToPeerCall) {
recyclerView = view.findViewById(R.id.grid_opponents)
- val context = activity!!
- recyclerView.addItemDecoration(DividerItemDecoration(context, R.dimen.grid_item_divider))
+ recyclerView.addItemDecoration(DividerItemDecoration(requireContext(), R.dimen.grid_item_divider))
recyclerView.setHasFixedSize(true)
val columnsCount = defineColumnsCount()
val layoutManager = LinearLayoutManager(activity, RecyclerView.HORIZONTAL, false)
@@ -153,7 +152,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
}
})
}
- connectionStatusLocal = view.findViewById(R.id.connection_status_local)
+ tvFullNameUser = view.findViewById(R.id.username_full_view)
cameraToggle = view.findViewById(R.id.toggle_camera)
cameraToggle.visibility = View.VISIBLE
@@ -177,16 +176,15 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
allOpponents = Collections.synchronizedList(ArrayList(opponents.size))
allOpponents.addAll(opponents)
- timerCallText = activity!!.findViewById(R.id.timer_call)
+ timerCallText = requireActivity().findViewById(R.id.timer_call)
isPeerToPeerCall = opponents.size == 1
}
override fun configureOutgoingScreen() {
- val context = activity!!
- outgoingOpponentsRelativeLayout.setBackgroundColor(ContextCompat.getColor(context, R.color.grey_transparent_50))
- allOpponentsTextView.setTextColor(ContextCompat.getColor(context, R.color.white))
- ringingTextView.setTextColor(ContextCompat.getColor(context, R.color.white))
+ outgoingOpponentsRelativeLayout.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.grey_transparent_50))
+ allOpponentsTextView.setTextColor(ContextCompat.getColor(requireContext(), R.color.white))
+ ringingTextView.setTextColor(ContextCompat.getColor(requireContext(), R.color.white))
}
override fun configureActionBar() {
@@ -194,23 +192,25 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
}
override fun configureToolbar() {
- val context = activity!!
- toolbar.visibility = View.VISIBLE
- toolbar.setBackgroundColor(ContextCompat.getColor(context, R.color.black_transparent_50))
- toolbar.setTitleTextColor(ContextCompat.getColor(context, R.color.white))
- toolbar.setSubtitleTextColor(ContextCompat.getColor(context, R.color.white))
+ toolbar?.visibility = View.VISIBLE
+ toolbar?.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.black_transparent_50))
+ toolbar?.setTitleTextColor(ContextCompat.getColor(requireContext(), R.color.white))
+ toolbar?.setSubtitleTextColor(ContextCompat.getColor(requireContext(), R.color.white))
}
private fun setDuringCallActionBar() {
- actionBar.setDisplayShowTitleEnabled(true)
- actionBar.title = currentUser.fullName
- if (isPeerToPeerCall) {
- actionBar.subtitle = getString(R.string.opponent, opponents[0].fullName)
+ actionBar.setDisplayShowTitleEnabled(false)
+ val user: QBUser? = if (isPeerToPeerCall) {
+ opponents[0]
} else {
- actionBar.subtitle = getString(R.string.opponents, amountOpponents.toString())
+ QbUsersDbManager.getUserById(userIdFullScreen)
}
- actionButtonsEnabled(true)
+ user?.let {
+ val name = it.fullName ?: it.login
+ tvFullNameUser.text = name
+ actionButtonsEnabled(true)
+ }
}
private fun addListeners() {
@@ -223,6 +223,8 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
conversationFragmentCallback?.removeSessionStateListener(this)
conversationFragmentCallback?.removeSessionEventsListener(this)
conversationFragmentCallback?.removeVideoTrackListener(this)
+ conversationFragmentCallback?.removeCallTimeUpdateListener(CallTimeUpdateListenerImpl(TAG))
+ conversationFragmentCallback?.removeUpdateOpponentsListener(UpdateOpponentsListenerImpl(TAG))
}
override fun actionButtonsEnabled(inability: Boolean) {
@@ -234,10 +236,10 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
private fun restoreSession() {
Log.d(TAG, "restoreSession ")
- if (conversationFragmentCallback?.isCallState() == false) {
+ if (conversationFragmentCallback?.isConnectedCall() == false) {
return
}
- onCallStarted()
+ startedCall()
val videoTrackMap = conversationFragmentCallback?.getVideoTrackMap() ?: return
if (videoTrackMap.isNotEmpty()) {
val entryIterator = videoTrackMap.entries.iterator()
@@ -249,12 +251,12 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
if (userId == currentUser.id) {
Log.d(TAG, "execute restoreSession for user:$userId")
- mainHandler.postDelayed({
+ mainHandler?.postDelayed({
onLocalVideoTrackReceive(null, videoTrack)
}, LOCAL_TRACK_INITIALIZE_DELAY)
} else if (conversationFragmentCallback?.getPeerChannel(userId) != QBRTCTypes.QBRTCConnectionState.QB_RTC_CONNECTION_CLOSED) {
Log.d(TAG, "execute restoreSession for user:$userId")
- mainHandler.postDelayed({
+ mainHandler?.postDelayed({
onConnectedToUser(null, userId)
onRemoteVideoTrackReceive(null, videoTrack, userId)
}, LOCAL_TRACK_INITIALIZE_DELAY)
@@ -287,8 +289,10 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
gridWidth?.let {
val cellSizeWidth = defineSize(it, columnsCount, itemMargin)
Log.i(TAG, "onGlobalLayout : cellSize=$cellSizeWidth")
- opponentsAdapter = OpponentsFromCallAdapter(context!!, this, opponents, cellSizeWidth,
- resources.getDimension(R.dimen.item_height).toInt())
+ opponentsAdapter = OpponentsFromCallAdapter(
+ requireContext(), this, opponents, cellSizeWidth,
+ resources.getDimension(R.dimen.item_height).toInt()
+ )
opponentsAdapter.setAdapterListener(this)
recyclerView.adapter = opponentsAdapter
}
@@ -323,11 +327,6 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
}
}
- override fun onCallStopped() {
- super.onCallStopped()
- Log.i(TAG, "onCallStopped")
- }
-
override fun initButtonsListener() {
super.initButtonsListener()
@@ -376,7 +375,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
return
}
val surfaceViewRenderer = if (isLocalVideoFullScreen) {
- remoteFullScreenVideoView!!
+ remoteFullScreenVideoView
} else {
localVideoView
}
@@ -411,11 +410,11 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
if (isPeerToPeerCall) {
setDuringCallActionBar()
remoteFullScreenVideoView?.let {
- fillVideoView(remoteFullScreenVideoView!!, videoTrack, true)
- updateVideoView(remoteFullScreenVideoView!!, false)
+ fillVideoView(remoteFullScreenVideoView, videoTrack, true)
+ updateVideoView(remoteFullScreenVideoView, false)
}
} else {
- mainHandler.postDelayed({ setRemoteViewMultiCall(it, videoTrack) }, LOCAL_TRACK_INITIALIZE_DELAY)
+ mainHandler?.postDelayed({ setRemoteViewMultiCall(it, videoTrack) }, LOCAL_TRACK_INITIALIZE_DELAY)
}
}
}
@@ -430,20 +429,23 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
val connectionState = conversationFragmentCallback?.getPeerChannel(userId)
val videoTrackMap = conversationFragmentCallback?.getVideoTrackMap()
- if (videoTrackMap != null && !videoTrackMap.containsKey(userId)
- || connectionState?.ordinal == QBRTCTypes.QBRTCConnectionState.QB_RTC_CONNECTION_CLOSED.ordinal) {
+ val isNotExistVideoTrack = videoTrackMap != null && !videoTrackMap.containsKey(userId)
+ val isConnectionStateClosed =
+ connectionState?.ordinal == QBRTCTypes.QBRTCConnectionState.QB_RTC_CONNECTION_CLOSED.ordinal
+ val holder = findHolder(userId)
+ if (isNotExistVideoTrack || isConnectionStateClosed || holder == null) {
return
}
replaceUsersInAdapter(position)
updateViewHolders(position)
- swapUsersFullscreenToPreview(userId)
+ swapUsersFullscreenToPreview(holder, userId)
}
private fun replaceUsersInAdapter(position: Int) {
val opponents = allOpponents
for (qbUser in opponents) {
- if (qbUser.id == userIDFullScreen) {
+ if (qbUser.id == userIdFullScreen) {
opponentsAdapter.replaceUsers(position, qbUser)
break
}
@@ -456,25 +458,24 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
opponentViewHolders.put(position, childViewHolder)
}
- private fun swapUsersFullscreenToPreview(userId: Int) {
- // get opponentVideoTrack - opponent's video track from recyclerView
- val videoTrackMap = conversationFragmentCallback?.getVideoTrackMap()
-
- val opponentVideoTrack = videoTrackMap?.get(userId)
+ private fun swapUsersFullscreenToPreview(holder: OpponentsFromCallAdapter.ViewHolder, userId: Int) {
+ val videoTrack = conversationFragmentCallback?.getVideoTrackMap()?.get(userId)
+ val videoTrackFullScreen = conversationFragmentCallback?.getVideoTrackMap()?.get(userIdFullScreen)
- // get mainVideoTrack - opponent's video track from full screen
- val mainVideoTrack = videoTrackMap?.get(userIDFullScreen)
+ val videoView = holder.getOpponentView()
- val remoteVideoView = findHolder(userId)?.getOpponentView()
-
- mainVideoTrack?.let {
- fillVideoView(0, remoteVideoView!!, it)
- Log.d(TAG, "_remoteVideoView enabled")
+ videoTrack?.let {
+ fillVideoView(userId, remoteFullScreenVideoView, videoTrack);
+ val user: QBUser? = QbUsersDbManager.getUserById(userIdFullScreen)
+ val name = user?.fullName ?: user?.login
+ tvFullNameUser.text = name
}
- opponentVideoTrack?.let {
- fillVideoView(userId, remoteFullScreenVideoView!!, it)
- Log.d(TAG, "fullscreen enabled")
+ if (videoTrackFullScreen != null) {
+ fillVideoView(0, videoView, videoTrackFullScreen)
+ } else {
+ holder.getOpponentView().setBackgroundColor(Color.BLACK)
+ remoteFullScreenVideoView?.setBackgroundColor(Color.TRANSPARENT)
}
}
@@ -493,20 +494,20 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
if (isRemoteShown) {
Log.d(TAG, "onRemoteVideoTrackReceive User = $userID")
fillVideoView(remoteVideoView, videoTrack, true)
+ showRecyclerView();
} else {
isRemoteShown = true
itemHolder.getOpponentView().release()
opponentsAdapter.removeItem(itemHolder.adapterPosition)
- setDuringCallActionBar()
- setRecyclerViewVisibleState()
remoteFullScreenVideoView?.let {
fillVideoView(userID, it, videoTrack)
- updateVideoView(remoteFullScreenVideoView!!, false)
+ updateVideoView(remoteFullScreenVideoView, false)
}
+ setDuringCallActionBar()
}
}
- private fun setRecyclerViewVisibleState() {
+ private fun showRecyclerView() {
val params = recyclerView.layoutParams
params.height = resources.getDimension(R.dimen.item_height).toInt()
recyclerView.layoutParams = params
@@ -555,10 +556,9 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
/**
* @param userId set userId if it from fullscreen videoTrack
*/
- private fun fillVideoView(videoView: QBRTCSurfaceView?, videoTrack: QBRTCVideoTrack,
- remoteRenderer: Boolean) {
- videoTrack.removeRenderer(videoTrack.renderer)
- videoTrack.addRenderer(videoView)
+ private fun fillVideoView(videoView: QBRTCSurfaceView?, videoTrack: QBRTCVideoTrack?, remoteRenderer: Boolean) {
+ videoTrack?.removeRenderer(videoTrack.renderer)
+ videoTrack?.addRenderer(videoView)
if (!remoteRenderer) {
updateVideoView(videoView, isCurrentCameraFront)
}
@@ -576,16 +576,15 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
/**
* @param userId set userId if it from fullscreen videoTrack
*/
- private fun fillVideoView(userId: Int, videoView: QBRTCSurfaceView, videoTrack: QBRTCVideoTrack) {
+ private fun fillVideoView(userId: Int, videoView: QBRTCSurfaceView?, videoTrack: QBRTCVideoTrack) {
if (userId != 0) {
- userIDFullScreen = userId
+ userIdFullScreen = userId
}
fillVideoView(videoView, videoTrack, true)
}
private fun setStatusForOpponent(userId: Int?, status: String) {
if (isPeerToPeerCall) {
- connectionStatusLocal.text = status
return
}
@@ -609,7 +608,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
}
}
- private fun setProgressBarForOpponentGone(userId: Int) {
+ private fun hideProgressForOpponent(userId: Int) {
if (isPeerToPeerCall) {
return
}
@@ -619,10 +618,11 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
}
private fun setBackgroundOpponentView(userId: Int?) {
- val holder = findHolder(userId) ?: return
-
- if (userId != userIDFullScreen) {
- holder.getOpponentView().setBackgroundColor(Color.parseColor("#000000"))
+ if (userId != userIdFullScreen) {
+ val holder = findHolder(userId) ?: return
+ holder.getOpponentView().setBackgroundColor(Color.BLACK)
+ } else {
+ remoteFullScreenVideoView?.setBackgroundColor(Color.BLACK)
}
}
@@ -633,7 +633,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
override fun onConnectedToUser(qbrtcSession: QBRTCSession?, userId: Int) {
connectionEstablished = true
setStatusForOpponent(userId, getString(R.string.text_status_connected))
- setProgressBarForOpponentGone(userId)
+ hideProgressForOpponent(userId)
}
override fun onConnectionClosedForUser(qbrtcSession: QBRTCSession, userId: Int?) {
@@ -642,6 +642,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
if (!isPeerToPeerCall) {
Log.d(TAG, "onConnectionClosedForUser videoTrackMap.remove(userId)= $userId")
setBackgroundOpponentView(it)
+ hideProgressForOpponent(userId);
}
}
}
@@ -651,7 +652,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
}
override fun onUserNotAnswer(session: QBRTCSession, userId: Int) {
- setProgressBarForOpponentGone(userId)
+ hideProgressForOpponent(userId)
setStatusForOpponent(userId, getString(R.string.text_status_no_answer))
}
@@ -667,7 +668,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
setStatusForOpponent(userId, getString(R.string.text_status_hang_up))
Log.d(TAG, "onReceiveHangUpFromUser userId= $userId")
if (!isPeerToPeerCall) {
- if (userId == userIDFullScreen) {
+ if (userId == userIdFullScreen) {
Log.d(TAG, "setAnotherUserToFullScreen call userId= $userId")
setAnotherUserToFullScreen()
}
@@ -682,19 +683,24 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
if (opponentsAdapter.opponents.isEmpty()) {
return
}
- for (user in opponents){
+ for (user in opponents) {
val videoTrack = conversationFragmentCallback?.getVideoTrack(user.id)
- if (videoTrack != null){
- val userFullScreen = QbUsersDbManager.getUserById(userIDFullScreen)
+ videoTrack?.let { track ->
+ val userFullScreen = QbUsersDbManager.getUserById(userIdFullScreen)
val itemHolder = findHolder(user.id)
- itemHolder?.setUserId(userIDFullScreen)
+
+ itemHolder?.setUserId(userIdFullScreen)
itemHolder?.setUserName(userFullScreen?.fullName.toString())
itemHolder?.setStatus(getString(R.string.text_status_closed))
itemHolder?.getOpponentView()?.release()
-
+ itemHolder?.adapterPosition?.let { position ->
+ replaceUsersInAdapter(position)
+ }
remoteFullScreenVideoView?.let {
- fillVideoView(user.id, it, videoTrack)
+ fillVideoView(user.id, it, track)
+ val name = user.fullName ?: user.login
+ tvFullNameUser.text = name
Log.d(TAG, "fullscreen enabled")
}
return
@@ -727,17 +733,6 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
conversationFragmentCallback?.onStartScreenSharing()
}
- override fun onOpponentsListUpdated(newUsers: ArrayList) {
- super.onOpponentsListUpdated(newUsers)
- updateAllOpponentsList(newUsers)
- Log.d(TAG, "updateOpponentsList(), newUsers = $newUsers")
- runUpdateUsersNames(newUsers)
- }
-
- override fun onCallTimeUpdate(time: String) {
- timerCallText.text = time
- }
-
private fun updateAllOpponentsList(newUsers: ArrayList) {
val indexList = allOpponents.indices
for (index in indexList) {
@@ -751,7 +746,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
private fun runUpdateUsersNames(newUsers: ArrayList) {
// need delayed for synchronization with recycler parentView initialization
- mainHandler.postDelayed({
+ mainHandler?.postDelayed({
for (user in newUsers) {
Log.d(TAG, "runUpdateUsersNames. foreach, user = " + user.fullName)
updateNameForOpponent(user.id, user.fullName)
@@ -792,7 +787,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
private fun hideToolBarAndButtons() {
actionBar.hide()
- localVideoView?.visibility = View.INVISIBLE
+ containerLocalVideoView?.visibility = View.INVISIBLE
actionVideoButtonsLayout.visibility = View.GONE
if (!isPeerToPeerCall) {
shiftBottomListOpponents()
@@ -801,7 +796,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
private fun showToolBarAndButtons() {
actionBar.show()
- localVideoView?.visibility = View.VISIBLE
+ containerLocalVideoView?.visibility = View.VISIBLE
actionVideoButtonsLayout.visibility = View.VISIBLE
if (!isPeerToPeerCall) {
shiftMarginListOpponents()
@@ -824,4 +819,44 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
recyclerView.layoutParams = params
}
}
+
+ private inner class UpdateOpponentsListenerImpl(val tag: String?) : CallActivity.UpdateOpponentsListener {
+ override fun updatedOpponents(updatedOpponents: ArrayList) {
+ updateAllOpponentsList(updatedOpponents)
+ Log.d(TAG, "updateOpponentsList(), opponents = $updatedOpponents")
+ runUpdateUsersNames(updatedOpponents)
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (other is UpdateOpponentsListenerImpl) {
+ return tag == other.tag
+ }
+ return false
+ }
+
+ override fun hashCode(): Int {
+ var hash = 1
+ hash = 31 * hash + tag.hashCode()
+ return hash
+ }
+ }
+
+ private inner class CallTimeUpdateListenerImpl(val tag: String?) : CallActivity.CallTimeUpdateListener {
+ override fun updatedCallTime(time: String) {
+ timerCallText.text = time
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (other is CallTimeUpdateListenerImpl) {
+ return tag == other.tag
+ }
+ return false
+ }
+
+ override fun hashCode(): Int {
+ var hash = 1
+ hash = 31 * hash + tag.hashCode()
+ return hash
+ }
+ }
}
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/services/CallService.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/services/CallService.kt
index 5c3595b69..424770b78 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/services/CallService.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/services/CallService.kt
@@ -4,7 +4,6 @@ import android.app.*
import android.content.Context
import android.content.Intent
import android.graphics.BitmapFactory
-import android.media.MediaPlayer
import android.os.Binder
import android.os.Build
import android.os.IBinder
@@ -14,7 +13,6 @@ import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import com.quickblox.chat.QBChatService
-import com.quickblox.core.QBEntityCallback
import com.quickblox.sample.videochat.kotlin.R
import com.quickblox.sample.videochat.kotlin.activities.CallActivity
import com.quickblox.sample.videochat.kotlin.db.QbUsersDbManager
@@ -23,10 +21,9 @@ import com.quickblox.sample.videochat.kotlin.fragments.IS_CURRENT_CAMERA_FRONT
import com.quickblox.sample.videochat.kotlin.fragments.MIC_ENABLED
import com.quickblox.sample.videochat.kotlin.fragments.SPEAKER_ENABLED
import com.quickblox.sample.videochat.kotlin.util.NetworkConnectionChecker
-import com.quickblox.sample.videochat.kotlin.util.loadUsersByIds
import com.quickblox.sample.videochat.kotlin.utils.*
-import com.quickblox.users.QBUsers
import com.quickblox.videochat.webrtc.*
+import com.quickblox.videochat.webrtc.BaseSession.QBRTCSessionState
import com.quickblox.videochat.webrtc.callbacks.*
import com.quickblox.videochat.webrtc.exception.QBRTCSignalException
import com.quickblox.videochat.webrtc.view.QBRTCVideoTrack
@@ -39,7 +36,7 @@ import kotlin.collections.HashMap
const val SERVICE_ID = 787
const val CHANNEL_ID = "Quickblox channel"
const val CHANNEL_NAME = "Quickblox background service"
-const val ONE_OPPONENT = 1
+const val MIN_OPPONENT_SIZE = 1
class CallService : Service() {
private var TAG = CallService::class.java.simpleName
@@ -60,7 +57,7 @@ class CallService : Service() {
private var currentSession: QBRTCSession? = null
private var expirationReconnectionTime: Long = 0
private var sharingScreenState: Boolean = false
- private var isCallState: Boolean = false
+ private var isConnectedCall: Boolean = false
private lateinit var rtcClient: QBRTCClient
private val callTimerTask: CallTimerTask = CallTimerTask()
@@ -153,7 +150,7 @@ class CallService : Service() {
builder.setContentTitle(notificationTitle)
builder.setContentText(notificationText)
builder.setWhen(System.currentTimeMillis())
- builder.setSmallIcon(R.mipmap.ic_launcher)
+ builder.setSmallIcon(R.drawable.ic_qb_logo)
val bitmapIcon = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher)
builder.setLargeIcon(bitmapIcon)
@@ -212,10 +209,7 @@ class CallService : Service() {
rtcClient = QBRTCClient.getInstance(this)
rtcClient.setCameraErrorHandler(CameraEventsListener())
- QBRTCConfig.setMaxOpponentsCount(MAX_OPPONENTS_COUNT)
- QBRTCConfig.setDebugEnabled(true)
-
- configRTCTimers(this)
+ applyRTCSettings()
rtcClient.prepareToProcessCalls()
}
@@ -414,8 +408,8 @@ class CallService : Service() {
return sharingScreenState
}
- fun isCallMode(): Boolean {
- return isCallState
+ fun isConnectedCall(): Boolean {
+ return isConnectedCall
}
fun getVideoTrackMap(): MutableMap {
@@ -426,13 +420,13 @@ class CallService : Service() {
videoTrackMap[userId] = videoTrack
}
- fun getVideoTrack(userId: Int): QBRTCVideoTrack? {
+ fun getVideoTrack(userId: Int?): QBRTCVideoTrack? {
return videoTrackMap[userId]
}
- private fun removeVideoTrack(userId: Int) {
+ private fun removeVideoTrack(userId: Int?) {
val videoTrack = getVideoTrack(userId)
- val renderer =videoTrack?.renderer
+ val renderer = videoTrack?.renderer
videoTrack?.removeRenderer(renderer)
videoTrackMap.remove(userId)
}
@@ -498,11 +492,8 @@ class CallService : Service() {
private inner class ConnectionListenerImpl : AbstractConnectionListener() {
override fun connectionClosedOnError(e: Exception?) {
- val sharedPref = PreferenceManager.getDefaultSharedPreferences(applicationContext)
- val reconnectHangUpTimeMillis = getPreferenceInt(sharedPref, applicationContext,
- R.string.pref_disconnect_time_interval_key,
- R.string.pref_disconnect_time_interval_default_value) * 1000
- expirationReconnectionTime = System.currentTimeMillis() + reconnectHangUpTimeMillis
+ val HANG_UP_TIME_10_SECONDS = 10 * 1000
+ expirationReconnectionTime = System.currentTimeMillis() + HANG_UP_TIME_10_SECONDS
}
override fun reconnectionSuccessful() {
@@ -510,7 +501,7 @@ class CallService : Service() {
override fun reconnectingIn(seconds: Int) {
Log.i(TAG, "reconnectingIn $seconds")
- if (!isCallState && expirationReconnectionTime < System.currentTimeMillis()) {
+ if (!isConnectedCall && expirationReconnectionTime < System.currentTimeMillis()) {
hangUpCurrentSession(HashMap())
}
}
@@ -529,18 +520,15 @@ class CallService : Service() {
stopRingtone()
if (session == WebRtcSessionManager.getCurrentSession()) {
val numberOpponents = session?.opponents?.size
- if (numberOpponents == ONE_OPPONENT) {
- currentSession?.let {
- it.hangUp(HashMap())
- CallService.stop(this@CallService)
+ if (numberOpponents == MIN_OPPONENT_SIZE || session?.state == QBRTCSessionState.QB_RTC_SESSION_PENDING) {
+ if (userID?.equals(session.callerID) == true){
+ currentSession?.hangUp(HashMap())
}
- }else{
+ } else {
userID?.let {
removeVideoTrack(it)
}
}
- } else {
- CallService.stop(this@CallService)
}
val participant = QbUsersDbManager.getUserById(userID)
@@ -574,8 +562,8 @@ class CallService : Service() {
override fun onSessionClosed(session: QBRTCSession?) {
Log.d(TAG, "Session " + session?.sessionID + " start stop session")
- stopRingtone()
if (session == currentSession) {
+ stopRingtone()
Log.d(TAG, "Stop session")
CallService.stop(this@CallService)
}
@@ -596,7 +584,7 @@ class CallService : Service() {
override fun onConnectedToUser(session: QBRTCSession?, userId: Int?) {
stopRingtone()
- isCallState = true
+ isConnectedCall = true
Log.d(TAG, "onConnectedToUser() is started")
startCallTimer()
}
@@ -604,6 +592,7 @@ class CallService : Service() {
override fun onConnectionClosedForUser(session: QBRTCSession?, userID: Int?) {
Log.d(TAG, "Connection closed for user: $userID")
shortToast("The user: " + userID + "has left the call")
+ removeVideoTrack(userID)
}
override fun onStateChanged(session: QBRTCSession?, sessionState: BaseSession.QBRTCSessionState?) {
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/services/LoginService.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/services/LoginService.kt
index bbddac507..3edcd7b67 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/services/LoginService.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/services/LoginService.kt
@@ -7,19 +7,17 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.IBinder
+import android.text.TextUtils
import android.util.Log
import com.quickblox.chat.QBChatService
import com.quickblox.chat.connections.tcp.QBTcpChatConnectionFabric
import com.quickblox.chat.connections.tcp.QBTcpConfigurationBuilder
import com.quickblox.core.QBEntityCallback
import com.quickblox.core.exception.QBResponseException
-import com.quickblox.sample.videochat.kotlin.util.ChatPingAlarmManager
import com.quickblox.sample.videochat.kotlin.utils.*
import com.quickblox.users.model.QBUser
import com.quickblox.videochat.webrtc.QBRTCClient
import com.quickblox.videochat.webrtc.QBRTCConfig
-import org.jivesoftware.smackx.ping.PingFailedListener
-
private const val EXTRA_COMMAND_TO_SERVICE = "command_for_service"
private const val EXTRA_QB_USER = "qb_user"
@@ -27,6 +25,7 @@ private const val EXTRA_QB_USER = "qb_user"
private const val COMMAND_NOT_FOUND = 0
private const val COMMAND_LOGIN = 1
private const val COMMAND_LOGOUT = 2
+private const val COMMAND_DESTROY_RTC_CLIENT = 3
private const val EXTRA_PENDING_INTENT = "pending_Intent"
@@ -39,7 +38,7 @@ class LoginService : Service() {
private var currentUser: QBUser? = null
companion object {
- fun start(context: Context, qbUser: QBUser, pendingIntent: PendingIntent? = null) {
+ fun loginToChatAndInitRTCClient(context: Context, qbUser: QBUser, pendingIntent: PendingIntent? = null) {
val intent = Intent(context, LoginService::class.java)
intent.putExtra(EXTRA_COMMAND_TO_SERVICE, COMMAND_LOGIN)
intent.putExtra(EXTRA_QB_USER, qbUser)
@@ -48,12 +47,13 @@ class LoginService : Service() {
context.startService(intent)
}
- fun stop(context: Context) {
+ fun logoutFromChat(context: Context) {
val intent = Intent(context, LoginService::class.java)
- context.stopService(intent)
+ intent.putExtra(EXTRA_COMMAND_TO_SERVICE, COMMAND_LOGOUT)
+ context.startService(intent)
}
- fun logout(context: Context) {
+ fun destroyRTCClient(context: Context) {
val intent = Intent(context, LoginService::class.java)
intent.putExtra(EXTRA_COMMAND_TO_SERVICE, COMMAND_LOGOUT)
context.startService(intent)
@@ -71,7 +71,7 @@ class LoginService : Service() {
parseIntentExtras(intent)
startSuitableActions()
- return Service.START_REDELIVER_INTENT
+ return START_REDELIVER_INTENT
}
private fun parseIntentExtras(intent: Intent?) {
@@ -86,10 +86,10 @@ class LoginService : Service() {
}
private fun startSuitableActions() {
- if (currentCommand == COMMAND_LOGIN) {
- startLoginToChat()
- } else if (currentCommand == COMMAND_LOGOUT) {
- logout()
+ when (currentCommand) {
+ COMMAND_LOGIN -> loginToChatAndInitRTCClient()
+ COMMAND_LOGOUT -> logoutFomChat()
+ COMMAND_DESTROY_RTC_CLIENT -> destroyRtcClient()
}
}
@@ -102,60 +102,46 @@ class LoginService : Service() {
chatService = QBChatService.getInstance()
}
- private fun startLoginToChat() {
+ private fun loginToChatAndInitRTCClient() {
if (chatService.isLoggedIn) {
sendResultToActivity(true, null)
} else {
currentUser?.let {
- loginToChat(it)
+ loginToChatAndInitRTCClient(it)
}
}
}
- private fun loginToChat(qbUser: QBUser) {
- chatService.login(qbUser, object : QBEntityCallback {
- override fun onSuccess(qbUser: QBUser?, bundle: Bundle) {
+ private fun loginToChatAndInitRTCClient(user: QBUser) {
+ chatService.login(user, object : QBEntityCallback {
+ override fun onSuccess(user: QBUser?, bundle: Bundle) {
Log.d(TAG, "login onSuccess")
- startActionsOnSuccessLogin()
+ initQBRTCClient()
+ sendResultToActivity(true, null)
}
override fun onError(e: QBResponseException) {
Log.d(TAG, "login onError " + e.message)
- val errorMessage = if (e.message != null) {
- e.message
- } else {
- "Login error"
+ var errorMessage: String? = e.message
+ if (TextUtils.isEmpty(errorMessage)) {
+ errorMessage = "Login error"
}
sendResultToActivity(false, errorMessage)
}
})
}
- private fun startActionsOnSuccessLogin() {
- initPingListener()
- initQBRTCClient()
- sendResultToActivity(true, null)
- }
-
- private fun initPingListener() {
- ChatPingAlarmManager.onCreate(this)
- ChatPingAlarmManager.addPingListener(PingFailedListener { Log.d(TAG, "Ping chat server failed") })
- }
-
private fun initQBRTCClient() {
rtcClient = QBRTCClient.getInstance(applicationContext)
- // Add signalling manager
- chatService.videoChatWebRTCSignalingManager?.addSignalingManagerListener { qbSignaling, createdLocally ->
- if (!createdLocally) {
- rtcClient.addSignaling(qbSignaling)
+ chatService.videoChatWebRTCSignalingManager?.addSignalingManagerListener { signaling, createdLocally ->
+ val needAddSignaling = !createdLocally
+ if (needAddSignaling) {
+ rtcClient.addSignaling(signaling)
}
}
- // Configure
- QBRTCConfig.setDebugEnabled(true)
- configRTCTimers(this)
+ applyRTCSettings()
- // Add service as callback to RTCClient
rtcClient.addSessionCallbacksListener(WebRtcSessionManager)
rtcClient.prepareToProcessCalls()
}
@@ -175,15 +161,14 @@ class LoginService : Service() {
}
}
- private fun logout() {
- destroyRtcClientAndChat()
- }
-
- private fun destroyRtcClientAndChat() {
+ private fun destroyRtcClient() {
if (::rtcClient.isInitialized) {
rtcClient.destroy()
}
- ChatPingAlarmManager.onDestroy()
+ stopSelf()
+ }
+
+ private fun logoutFomChat() {
chatService.logout(object : QBEntityCallback {
override fun onSuccess(aVoid: Void?, bundle: Bundle) {
chatService.destroy()
@@ -197,11 +182,6 @@ class LoginService : Service() {
stopSelf()
}
- override fun onDestroy() {
- Log.d(TAG, "Service onDestroy()")
- super.onDestroy()
- }
-
override fun onBind(intent: Intent): IBinder? {
Log.d(TAG, "Service onBind)")
return null
@@ -210,19 +190,20 @@ class LoginService : Service() {
override fun onTaskRemoved(rootIntent: Intent) {
Log.d(TAG, "Service onTaskRemoved()")
super.onTaskRemoved(rootIntent)
- if (!isCallServiceRunning()) {
- logout()
+ if (isCallServiceNotRunning()) {
+ logoutFomChat()
+ destroyRtcClient()
}
}
- private fun isCallServiceRunning(): Boolean {
+ private fun isCallServiceNotRunning(): Boolean {
val manager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
- var running = false
+ var notRunning = true
for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
if (CallService::class.java.name == service.service.className) {
- running = true
+ notRunning = false
}
}
- return running
+ return notRunning
}
}
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/services/fcm/PushListenerService.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/services/fcm/PushListenerService.kt
index aaced2995..63e281b74 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/services/fcm/PushListenerService.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/services/fcm/PushListenerService.kt
@@ -12,10 +12,10 @@ class PushListenerService : QBFcmPushListenerService() {
override fun onMessageReceived(remoteMessage: RemoteMessage?) {
super.onMessageReceived(remoteMessage)
- if (SharedPrefsHelper.hasQbUser()) {
- val qbUser: QBUser = SharedPrefsHelper.getQbUser()
- Log.d(TAG, "App has logged user" + qbUser.id)
- LoginService.start(this, qbUser)
+ if (SharedPrefsHelper.hasCurrentUser()) {
+ val user: QBUser = SharedPrefsHelper.getCurrentUser()
+ Log.d(TAG, "App has logged user" + user.id)
+ LoginService.loginToChatAndInitRTCClient(this, user)
}
}
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/util/ChatPingAlarmManager.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/util/ChatPingAlarmManager.kt
deleted file mode 100644
index 6adffca8f..000000000
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/util/ChatPingAlarmManager.kt
+++ /dev/null
@@ -1,88 +0,0 @@
-package com.quickblox.sample.videochat.kotlin.util
-
-import android.app.AlarmManager
-import android.app.PendingIntent
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-import android.content.IntentFilter
-import android.os.Build
-import android.os.Bundle
-import android.os.SystemClock
-import android.util.Log
-import com.quickblox.chat.QBChatService
-import com.quickblox.core.QBEntityCallback
-import com.quickblox.core.exception.QBResponseException
-import org.jivesoftware.smackx.ping.PingFailedListener
-import java.lang.ref.WeakReference
-import java.util.concurrent.TimeUnit
-
-
-private const val PING_ALARM_ACTION = "com.quickblox.chat.ping.ACTION"
-
-object ChatPingAlarmManager {
- private val TAG = ChatPingAlarmManager::class.java.simpleName
- private val PING_INTERVAL = TimeUnit.SECONDS.toMillis(60)
- private lateinit var pendingIntent: PendingIntent
- private lateinit var alarmManager: AlarmManager
- private lateinit var context: WeakReference
- private var pingFailedListener: PingFailedListener? = null
-
- private val alarmBroadcastReceiver = object : BroadcastReceiver() {
- override fun onReceive(context: Context, intent: Intent) {
- Log.v(TAG, "Ping Alarm broadcast received")
- Log.d(TAG, "Calling pingServer for connection ")
- val pingManager = QBChatService.getInstance().pingManager
- pingManager?.pingServer(object : QBEntityCallback {
- override fun onSuccess(result: Void?, params: Bundle) {
-
- }
-
- override fun onError(responseException: QBResponseException) {
- pingFailedListener?.pingFailed()
- }
- })
- }
- }
-
- /**
- * Register a pending intent with the AlarmManager to be broadcasted every
- * half hour and register the alarm broadcast receiver to receive this
- * intent. The receiver will check all known questions if a ping is
- * Necessary when invoked by the alarm intent.
- *
- * @param context
- */
- fun onCreate(context: Context) {
- var intentFlag = 0
-
- this.context = WeakReference(context)
- context.registerReceiver(alarmBroadcastReceiver, IntentFilter(PING_ALARM_ACTION))
- alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- intentFlag = PendingIntent.FLAG_IMMUTABLE
- }
-
- pendingIntent = PendingIntent.getBroadcast(context, 0, Intent(PING_ALARM_ACTION), intentFlag)
- val trigger = SystemClock.elapsedRealtime() + PING_INTERVAL
- alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, trigger, PING_INTERVAL, pendingIntent)
- }
-
- /**
- * Unregister the alarm broadcast receiver and cancel the alarm.
- */
- fun onDestroy() {
- try {
- context.get()?.unregisterReceiver(alarmBroadcastReceiver)
- } catch (e: IllegalArgumentException) {
- e.printStackTrace()
- }
- alarmManager.cancel(pendingIntent)
- pingFailedListener = null
- }
-
- fun addPingListener(listener: PingFailedListener) {
- pingFailedListener = listener
- }
-}
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/util/QBResRequestExecutor.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/util/QBResRequestExecutor.kt
deleted file mode 100644
index 4633da893..000000000
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/util/QBResRequestExecutor.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.quickblox.sample.videochat.kotlin.util
-
-import com.quickblox.core.QBEntityCallback
-import com.quickblox.core.request.QBPagedRequestBuilder
-import com.quickblox.users.QBUsers
-import com.quickblox.users.model.QBUser
-import java.util.*
-
-fun signUp(newQbUser: QBUser, callback: QBEntityCallback) {
- QBUsers.signUp(newQbUser).performAsync(callback)
-}
-
-fun signInUser(currentQbUser: QBUser, callback: QBEntityCallback) {
- QBUsers.signIn(currentQbUser).performAsync(callback)
-}
-
-fun signOut() {
- QBUsers.signOut().performAsync(null)
-}
-
-fun deleteCurrentUser(currentQbUserID: Int, callback: QBEntityCallback) {
- QBUsers.deleteUser(currentQbUserID).performAsync(callback)
-}
-
-fun loadUsersByTag(tag: String, callback: QBEntityCallback>) {
- val requestBuilder = QBPagedRequestBuilder()
- requestBuilder.perPage = 50
- val tags = LinkedList()
- tags.add(tag)
- QBUsers.getUsersByTags(tags, requestBuilder).performAsync(callback)
-}
-
-fun loadUsersByPagedRequestBuilder(callback: QBEntityCallback>, requestBuilder: QBPagedRequestBuilder) {
- QBUsers.getUsers(requestBuilder).performAsync(callback)
-}
-
-fun loadUsersByIds(usersIDs: Collection, callback: QBEntityCallback>) {
- QBUsers.getUsersByIDs(usersIDs, null).performAsync(callback)
-}
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/Consts.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/Consts.kt
index d6e571649..9a35b9c0b 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/Consts.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/Consts.kt
@@ -4,7 +4,7 @@ import android.Manifest
val PERMISSIONS = arrayOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO)
-const val MAX_OPPONENTS_COUNT = 6
+const val MAX_OPPONENTS_COUNT = 3
const val EXTRA_LOGIN_RESULT = "login_result"
@@ -12,8 +12,4 @@ const val EXTRA_LOGIN_ERROR_MESSAGE = "login_error_message"
const val EXTRA_LOGIN_RESULT_CODE = 1002
-const val EXTRA_IS_INCOMING_CALL = "conversation_reason"
-
-const val MAX_LOGIN_LENGTH = 15
-
-const val MAX_FULLNAME_LENGTH = 20
\ No newline at end of file
+const val EXTRA_IS_INCOMING_CALL = "conversation_reason"
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/KeyboardUtils.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/KeyboardUtils.kt
index 9d7285d05..86b21c013 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/KeyboardUtils.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/KeyboardUtils.kt
@@ -1,6 +1,7 @@
package com.quickblox.sample.videochat.kotlin.utils
import android.content.Context
+import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import com.quickblox.sample.videochat.kotlin.App
@@ -10,7 +11,7 @@ fun showKeyboard(editText: EditText) {
imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT)
}
-fun hideKeyboard(editText: EditText) {
+fun hideKeyboard(view: View) {
val imm = App.getInstance().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
- imm.hideSoftInputFromWindow(editText.windowToken, 0)
+ imm.hideSoftInputFromWindow(view.windowToken, 0)
}
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/PushNotificationSender.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/PushNotificationSender.kt
index 46ca2caf9..2d0824e13 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/PushNotificationSender.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/PushNotificationSender.kt
@@ -8,37 +8,35 @@ import com.quickblox.messages.model.QBNotificationType
import com.quickblox.sample.videochat.kotlin.R
import org.json.JSONException
import org.json.JSONObject
-import java.util.*
-fun sendPushMessage(recipients: ArrayList, senderName: String, newSessionID: String,
- opponentsIDs: String, opponentsNames: String, isVideoCall: Boolean) {
+fun sendPushMessage(userId: Int, senderName: String, sessionId: String,
+ opponentIds: String, opponentNames: String, isVideoCall: Boolean) {
val outMessage = String.format(R.string.text_push_notification_message.toString(), senderName)
- val timeStamp = System.currentTimeMillis()
-
- // Send Push: create QuickBlox Push Notification Event
+ // send Push: create QuickBlox Push Notification Event
val qbEvent = QBEvent()
qbEvent.notificationType = QBNotificationType.PUSH
qbEvent.environment = QBEnvironment.DEVELOPMENT
- // Generic push - will be delivered to all platforms (Android, iOS, WP, Blackberry..)
+ // generic push - will be delivered to all platforms (Android, iOS, WP, Blackberry..)
val json = JSONObject()
try {
json.put("message", outMessage)
json.put("ios_voip", "1")
json.put("VOIPCall", "1")
- json.put("sessionID", newSessionID)
- json.put("opponentsIDs", opponentsIDs)
- json.put("contactIdentifier", opponentsNames)
+ json.put("sessionID", sessionId)
+ json.put("opponentsIDs", opponentIds)
+ json.put("contactIdentifier", opponentNames)
json.put("conferenceType", if (isVideoCall) "1" else "2")
- json.put("timestamp", timeStamp.toString())
+ json.put("timestamp", System.currentTimeMillis().toString())
} catch (e: JSONException) {
e.printStackTrace()
}
qbEvent.message = json.toString()
- val userIds = StringifyArrayList(recipients)
+ val userIds = StringifyArrayList()
+ userIds.add(userId)
qbEvent.userIds = userIds
QBPushNotifications.createEvent(qbEvent).performAsync(null)
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/SettingsManager.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/SettingsManager.kt
new file mode 100644
index 000000000..f7f5683fe
--- /dev/null
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/SettingsManager.kt
@@ -0,0 +1,37 @@
+package com.quickblox.sample.videochat.kotlin.utils
+
+import com.quickblox.videochat.webrtc.QBRTCConfig
+import com.quickblox.videochat.webrtc.QBRTCMediaConfig
+
+fun applyMediaSettings() {
+ applyAudioSettings()
+ applyVideoSettings()
+}
+
+private fun applyAudioSettings() {
+ QBRTCMediaConfig.setAudioCodec(QBRTCMediaConfig.AudioCodec.ISAC)
+ QBRTCMediaConfig.setUseBuildInAEC(true)
+ QBRTCMediaConfig.setAudioProcessingEnabled(true)
+ QBRTCMediaConfig.setUseOpenSLES(false)
+}
+
+private fun applyVideoSettings() {
+ QBRTCMediaConfig.setVideoHWAcceleration(true)
+ QBRTCMediaConfig.setVideoWidth(QBRTCMediaConfig.VideoQuality.VGA_VIDEO.width)
+ QBRTCMediaConfig.setVideoHeight(QBRTCMediaConfig.VideoQuality.VGA_VIDEO.height)
+ QBRTCMediaConfig.setVideoCodec(QBRTCMediaConfig.VideoCodec.VP8)
+}
+
+fun applyRTCSettings() {
+ QBRTCConfig.setMaxOpponentsCount(MAX_OPPONENTS_COUNT)
+ QBRTCConfig.setDebugEnabled(true)
+
+ val ANSWER_TIME_INTERVAL_IN_SECONDS = 30L
+ QBRTCConfig.setAnswerTimeInterval(ANSWER_TIME_INTERVAL_IN_SECONDS)
+
+ val DISCONNECT_TIME_IN_SECONDS = 10
+ QBRTCConfig.setDisconnectTime(DISCONNECT_TIME_IN_SECONDS)
+
+ val DIALING_TIME_INTERVAL_IN_SECONDS = 5L
+ QBRTCConfig.setDialingTimeInterval(DIALING_TIME_INTERVAL_IN_SECONDS)
+}
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/SettingsUtil.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/SettingsUtil.kt
deleted file mode 100644
index e85bb0b05..000000000
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/SettingsUtil.kt
+++ /dev/null
@@ -1,178 +0,0 @@
-package com.quickblox.sample.videochat.kotlin.utils
-
-import android.content.Context
-import android.content.SharedPreferences
-import android.preference.PreferenceManager
-import android.util.Log
-import com.quickblox.sample.videochat.kotlin.R
-import com.quickblox.videochat.webrtc.QBRTCConfig
-import com.quickblox.videochat.webrtc.QBRTCMediaConfig
-
-private val TAG = "SettingsUtil"
-private const val LIMIT_MEMBERS = 4
-
-private fun setSettingsForMultiCall(users: List) {
- if (users.size <= LIMIT_MEMBERS) {
- setDefaultVideoQuality()
- } else {
- //set to minimum settings
- QBRTCMediaConfig.setVideoWidth(QBRTCMediaConfig.VideoQuality.QBGA_VIDEO.width)
- QBRTCMediaConfig.setVideoHeight(QBRTCMediaConfig.VideoQuality.QBGA_VIDEO.height)
- QBRTCMediaConfig.setVideoHWAcceleration(false)
- QBRTCMediaConfig.setVideoCodec(null)
- }
-}
-
-fun setSettingsStrategy(users: List, sharedPref: SharedPreferences, context: Context) {
- setCommonSettings(sharedPref, context)
- if (users.size == 1) {
- setSettingsFromPreferences(sharedPref, context)
- } else {
- setSettingsForMultiCall(users)
- }
-}
-
-fun configRTCTimers(context: Context) {
- val sharedPref = PreferenceManager.getDefaultSharedPreferences(context)
-
- val answerTimeInterval = getPreferenceInt(sharedPref, context,
- R.string.pref_answer_time_interval_key,
- R.string.pref_answer_time_interval_default_value).toLong()
- QBRTCConfig.setAnswerTimeInterval(answerTimeInterval)
- Log.e(TAG, "answerTimeInterval = $answerTimeInterval")
-
- val disconnectTimeInterval = getPreferenceInt(sharedPref, context,
- R.string.pref_disconnect_time_interval_key,
- R.string.pref_disconnect_time_interval_default_value)
- QBRTCConfig.setDisconnectTime(disconnectTimeInterval)
- Log.e(TAG, "disconnectTimeInterval = $disconnectTimeInterval")
-
- val dialingTimeInterval = getPreferenceInt(sharedPref, context,
- R.string.pref_dialing_time_interval_key,
- R.string.pref_dialing_time_interval_default_value).toLong()
- QBRTCConfig.setDialingTimeInterval(dialingTimeInterval)
- Log.e(TAG, "dialingTimeInterval = $dialingTimeInterval")
-}
-
-fun isManageSpeakerPhoneByProximity(context: Context): Boolean {
- val sharedPref = PreferenceManager.getDefaultSharedPreferences(context)
- return sharedPref.getBoolean(context.getString(R.string.pref_manage_speakerphone_by_proximity_key),
- java.lang.Boolean.valueOf(context.getString(R.string.pref_manage_speakerphone_by_proximity_default)))
-}
-
-fun getPreferenceInt(sharedPref: SharedPreferences, context: Context, strResKey: Int, strResDefValue: Int): Int {
- return sharedPref.getInt(context.getString(strResKey), Integer.valueOf(context.getString(strResDefValue)))
-}
-
-private fun setCommonSettings(sharedPref: SharedPreferences, context: Context) {
- val audioCodecDescription = getPreferenceString(sharedPref, context, R.string.pref_audiocodec_key,
- R.string.pref_audiocodec_def)
- val audioCodec = if (QBRTCMediaConfig.AudioCodec.ISAC.description == audioCodecDescription) {
- QBRTCMediaConfig.AudioCodec.ISAC
- } else {
- QBRTCMediaConfig.AudioCodec.OPUS
- }
- Log.e(TAG, "audioCodec =: " + audioCodec.description)
- QBRTCMediaConfig.setAudioCodec(audioCodec)
- Log.v(TAG, "audioCodec = " + QBRTCMediaConfig.getAudioCodec())
-
- // Check Disable built-in AEC flag.
- val disableBuiltInAEC = getPreferenceBoolean(sharedPref, context,
- R.string.pref_disable_built_in_aec_key,
- R.string.pref_disable_built_in_aec_default)
- QBRTCMediaConfig.setUseBuildInAEC(!disableBuiltInAEC)
- Log.v(TAG, "setUseBuildInAEC = " + QBRTCMediaConfig.isUseBuildInAEC())
-
- // Check Disable Audio Processing flag.
- val noAudioProcessing = getPreferenceBoolean(sharedPref, context,
- R.string.pref_noaudioprocessing_key,
- R.string.pref_noaudioprocessing_default)
- QBRTCMediaConfig.setAudioProcessingEnabled(!noAudioProcessing)
- Log.v(TAG, "isAudioProcessingEnabled = " + QBRTCMediaConfig.isAudioProcessingEnabled())
-
- // Check OpenSL ES enabled flag.
- val useOpenSLES = getPreferenceBoolean(sharedPref, context,
- R.string.pref_opensles_key,
- R.string.pref_opensles_default)
- QBRTCMediaConfig.setUseOpenSLES(useOpenSLES)
- Log.v(TAG, "isUseOpenSLES = " + QBRTCMediaConfig.isUseOpenSLES())
-}
-
-private fun setSettingsFromPreferences(sharedPref: SharedPreferences, context: Context) {
-
- // Check HW codec flag.
- val hwCodec = sharedPref.getBoolean(context.getString(R.string.pref_hwcodec_key),
- java.lang.Boolean.valueOf(context.getString(R.string.pref_hwcodec_default)))
-
- QBRTCMediaConfig.setVideoHWAcceleration(hwCodec)
-
- // Get video resolution from settings.
- val resolutionDefaultValue = "0"
- val resolutionItem = Integer.parseInt(sharedPref.getString(context.getString(R.string.pref_resolution_key), resolutionDefaultValue)
- ?: resolutionDefaultValue)
- Log.e(TAG, "resolutionItem =: $resolutionItem")
- setVideoQuality(resolutionItem)
- Log.v(TAG, "resolution = " + QBRTCMediaConfig.getVideoHeight() + "x" + QBRTCMediaConfig.getVideoWidth())
-
- // Get start bitrate.
- val startBitrate = getPreferenceInt(sharedPref, context,
- R.string.pref_startbitratevalue_key,
- R.string.pref_startbitratevalue_default)
- Log.e(TAG, "videoStartBitrate =: $startBitrate")
- QBRTCMediaConfig.setVideoStartBitrate(startBitrate)
- Log.v(TAG, "videoStartBitrate = " + QBRTCMediaConfig.getVideoStartBitrate())
-
- val videoCodecDefaultValue = "0"
- val videoCodecItem = Integer.parseInt(getPreferenceString(sharedPref, context, R.string.pref_videocodec_key, videoCodecDefaultValue)
- ?: videoCodecDefaultValue)
- for (codec in QBRTCMediaConfig.VideoCodec.values()) {
- if (codec.ordinal == videoCodecItem) {
- Log.e(TAG, "videoCodecItem =: " + codec.description)
- QBRTCMediaConfig.setVideoCodec(codec)
- Log.v(TAG, "videoCodecItem = " + QBRTCMediaConfig.getVideoCodec())
- break
- }
- }
-
- // Get camera fps from settings.
- val cameraFps = getPreferenceInt(sharedPref, context, R.string.pref_frame_rate_key, R.string.pref_frame_rate_default)
- Log.e(TAG, "cameraFps = $cameraFps")
- QBRTCMediaConfig.setVideoFps(cameraFps)
- Log.v(TAG, "cameraFps = " + QBRTCMediaConfig.getVideoFps())
-}
-
-private fun setVideoQuality(resolutionItem: Int) {
- if (resolutionItem != -1) {
- setVideoFromLibraryPreferences(resolutionItem)
- } else {
- setDefaultVideoQuality()
- }
-}
-
-private fun setDefaultVideoQuality() {
- QBRTCMediaConfig.setVideoWidth(QBRTCMediaConfig.VideoQuality.VGA_VIDEO.width)
- QBRTCMediaConfig.setVideoHeight(QBRTCMediaConfig.VideoQuality.VGA_VIDEO.height)
-}
-
-private fun setVideoFromLibraryPreferences(resolutionItem: Int) {
- for (quality in QBRTCMediaConfig.VideoQuality.values()) {
- if (quality.ordinal == resolutionItem) {
- Log.e(TAG, "resolution =: " + quality.height + ":" + quality.width)
- QBRTCMediaConfig.setVideoHeight(quality.height)
- QBRTCMediaConfig.setVideoWidth(quality.width)
- }
- }
-}
-
-private fun getPreferenceString(sharedPref: SharedPreferences, context: Context, strResKey: Int, strResDefValue: Int): String {
- val defaultValue = context.getString(strResDefValue)
- return sharedPref.getString(context.getString(strResKey), defaultValue) ?: defaultValue
-}
-
-private fun getPreferenceString(sharedPref: SharedPreferences, context: Context, strResKey: Int, strResDefValue: String): String? {
- return sharedPref.getString(context.getString(strResKey), strResDefValue)
-}
-
-private fun getPreferenceBoolean(sharedPref: SharedPreferences, context: Context, StrRes: Int, strResDefValue: Int): Boolean {
- return sharedPref.getBoolean(context.getString(StrRes), java.lang.Boolean.valueOf(context.getString(strResDefValue)))
-}
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/SharedPrefsHelper.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/SharedPrefsHelper.kt
index b31900b20..71b1ac9f5 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/SharedPrefsHelper.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/SharedPrefsHelper.kt
@@ -7,7 +7,6 @@ import com.quickblox.core.helper.StringifyArrayList
import com.quickblox.sample.videochat.kotlin.App
import com.quickblox.users.model.QBUser
-
private const val SHARED_PREFS_NAME = "qb"
private const val QB_USER_ID = "qb_user_id"
private const val QB_USER_LOGIN = "qb_user_login"
@@ -16,8 +15,8 @@ private const val QB_USER_FULL_NAME = "qb_user_full_name"
private const val QB_USER_TAGS = "qb_user_tags"
object SharedPrefsHelper {
-
- private var sharedPreferences: SharedPreferences = App.getInstance().getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE)
+ private var sharedPreferences: SharedPreferences =
+ App.getInstance().getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE)
fun delete(key: String) {
if (sharedPreferences.contains(key)) {
@@ -39,19 +38,19 @@ object SharedPrefsHelper {
editor.apply()
}
- fun saveQbUser(qbUser: QBUser) {
- save(QB_USER_ID, qbUser.id)
- save(QB_USER_LOGIN, qbUser.login)
- save(QB_USER_PASSWORD, qbUser.password)
- save(QB_USER_FULL_NAME, qbUser.fullName)
- save(QB_USER_TAGS, qbUser.tags.itemsAsString)
+ fun saveCurrentUser(user: QBUser) {
+ save(QB_USER_ID, user.id)
+ save(QB_USER_LOGIN, user.login)
+ save(QB_USER_PASSWORD, user.password)
+ save(QB_USER_FULL_NAME, user.fullName)
+ save(QB_USER_TAGS, user.tags.itemsAsString)
}
fun clearAllData() {
sharedPreferences.edit().clear().apply()
}
- fun hasQbUser(): Boolean {
+ fun hasCurrentUser(): Boolean {
return has(QB_USER_LOGIN) && has(QB_USER_PASSWORD)
}
@@ -70,7 +69,7 @@ object SharedPrefsHelper {
return sharedPreferences.contains(key)
}
- fun getQbUser(): QBUser {
+ fun getCurrentUser(): QBUser {
val id = get(QB_USER_ID)
val login = get(QB_USER_LOGIN)
val password = get(QB_USER_PASSWORD)
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/ValidationUtils.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/ValidationUtils.kt
index 9ad027c1a..a95121678 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/ValidationUtils.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/utils/ValidationUtils.kt
@@ -1,42 +1,29 @@
package com.quickblox.sample.videochat.kotlin.utils
-import android.content.Context
import android.text.TextUtils
-import android.widget.EditText
-import com.quickblox.sample.videochat.kotlin.R
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.util.regex.Pattern
-private fun isEnteredTextValid(context: Context, editText: EditText, resFieldName: Int, maxLength: Int, checkName: Boolean): Boolean {
+private fun checkTextByPattern(text: String, pattern: Pattern): Boolean {
var isCorrect = false
- val p: Pattern
- if (checkName) {
- p = Pattern.compile("^[a-zA-Z][a-zA-Z0-9]{2," + (maxLength - 1) + "}+$")
- } else {
- p = Pattern.compile("^[a-zA-Z][a-zA-Z 0-9]{2," + (maxLength - 1) + "}+$")
- }
- if (editText.text.toString().isNotBlank()) {
- val m = p.matcher(editText.text.toString().trim { it <= ' ' })
- isCorrect = m.matches()
- }
- if (!isCorrect) {
- editText.error = String.format(context.getString(R.string.error_name_must_not_contain_special_characters_from_app),
- context.getString(resFieldName),
- maxLength)
- return false
- } else {
- return true
+
+ if (text.isNotBlank()) {
+ val matcher = pattern.matcher(text.trim { it <= ' ' })
+ isCorrect = matcher.matches()
}
+ return isCorrect
}
-fun isLoginValid(context: Context, editText: EditText): Boolean {
- return isEnteredTextValid(context, editText, R.string.field_name_user_login, MAX_LOGIN_LENGTH, true)
+fun isLoginValid(login: String): Boolean {
+ val pattern = Pattern.compile("^[a-zA-Z][a-zA-Z0-9]{2,49}+$")
+ return checkTextByPattern(login, pattern)
}
-fun isFoolNameValid(context: Context, editText: EditText): Boolean {
- return isEnteredTextValid(context, editText, R.string.field_name_user_fullname, MAX_FULLNAME_LENGTH, false)
+fun isDisplayNameValid(displayName: String): Boolean {
+ val pattern = Pattern.compile("^[a-zA-Z][a-zA-Z 0-9]{2,19}+$")
+ return checkTextByPattern(displayName, pattern)
}
fun isMiUi(): Boolean {
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/view/ListPreferenceCompat.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/view/ListPreferenceCompat.kt
deleted file mode 100644
index 5971b8598..000000000
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/view/ListPreferenceCompat.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.quickblox.sample.videochat.kotlin.view
-
-import android.annotation.TargetApi
-import android.content.Context
-import android.os.Build
-import android.preference.ListPreference
-import android.text.TextUtils
-import android.util.AttributeSet
-
-
-class ListPreferenceCompat : ListPreference {
-
- constructor(context: Context) : super(context)
-
- constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
-
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
-
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
-
- override fun setValue(value: String) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- super.setValue(value)
- } else {
- val oldValue = getValue()
- super.setValue(value)
- if (!TextUtils.equals(value, oldValue)) {
- notifyChanged()
- }
- }
- }
-}
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/view/SeekBarPreference.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/view/SeekBarPreference.kt
deleted file mode 100644
index 909227ad1..000000000
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/view/SeekBarPreference.kt
+++ /dev/null
@@ -1,101 +0,0 @@
-package com.quickblox.sample.videochat.kotlin.view
-
-import android.content.Context
-import android.content.res.TypedArray
-import android.preference.Preference
-import android.util.AttributeSet
-import android.util.Log
-import android.view.View
-import android.widget.SeekBar
-import com.quickblox.sample.videochat.kotlin.R
-
-private const val ANDROID_NS = "http://schemas.android.com/apk/res/android"
-private const val SEEKBAR_NS = "http://schemas.android.com/apk/res-auto"
-
-class SeekBarPreference : Preference, SeekBar.OnSeekBarChangeListener {
-
- private lateinit var seekBar: SeekBar
- private var progress: Int = 0
- private var maxSeekBarValue: Int = 0
- private var minSeekBarValue: Int = 0
- private var seekBarStepSize: Int = 0
-
- constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
- layoutResource = R.layout.seekbar_preference
- initFields(context, attrs)
- }
-
- constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
- layoutResource = R.layout.seekbar_preference
- initFields(context, attrs)
- }
-
- private fun initFields(context: Context, attrs: AttributeSet) {
- val maxValueResourceId = attrs.getAttributeResourceValue(ANDROID_NS, "max", R.integer.pref_default_int_value)
- maxSeekBarValue = context.resources.getInteger(maxValueResourceId)
-
- val minValueResourceId = attrs.getAttributeResourceValue(SEEKBAR_NS, "min", R.integer.pref_default_int_value)
- minSeekBarValue = context.resources.getInteger(minValueResourceId)
-
- val stepSizeValueResourceId = attrs.getAttributeResourceValue(SEEKBAR_NS, "stepSize", R.integer.pref_seekbar_step_default_int_value)
- seekBarStepSize = context.resources.getInteger(stepSizeValueResourceId)
-
- Log.v("Attribute", "max = $maxSeekBarValue")
- Log.v("Attribute", "min = $minSeekBarValue")
- Log.v("Attribute", "step = $seekBarStepSize")
- }
-
- override fun onBindView(view: View) {
- super.onBindView(view)
- seekBar = view.findViewById(R.id.seekbar)
- seekBar.max = maxSeekBarValue
- seekBar.progress = progress
- seekBar.setOnSeekBarChangeListener(this)
- }
-
- override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
- if (fromUser) {
- var changedProgress = progress / seekBarStepSize * seekBarStepSize
-
- if (changedProgress <= minSeekBarValue) {
- changedProgress += minSeekBarValue
- }
-
- setValue(changedProgress)
- }
- }
-
- override fun onStartTrackingTouch(seekBar: SeekBar) {
-
- }
-
- override fun onStopTrackingTouch(seekBar: SeekBar) {
-
- }
-
- override fun onSetInitialValue(restoreValue: Boolean, defaultValue: Any?) {
- val value = if (restoreValue) {
- getPersistedInt(progress)
- } else {
- defaultValue
- }
- setValue(value as Int)
- }
-
- private fun setValue(value: Int) {
- if (shouldPersist()) {
- persistInt(value)
- }
-
- if (value != progress) {
- progress = value
- notifyChanged()
- }
-
- summary = progress.toString()
- }
-
- override fun onGetDefaultValue(a: TypedArray, index: Int): Any {
- return a.getInt(index, 0)
- }
-}
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/res/drawable/ic_qb_logo.xml b/sample-videochat-kotlin/app/src/main/res/drawable/ic_qb_logo.xml
new file mode 100644
index 000000000..e541d52be
--- /dev/null
+++ b/sample-videochat-kotlin/app/src/main/res/drawable/ic_qb_logo.xml
@@ -0,0 +1,12 @@
+
+
+
diff --git a/sample-videochat-kotlin/app/src/main/res/layout/activity_login.xml b/sample-videochat-kotlin/app/src/main/res/layout/activity_login.xml
index 78008bbeb..a22ca75f7 100644
--- a/sample-videochat-kotlin/app/src/main/res/layout/activity_login.xml
+++ b/sample-videochat-kotlin/app/src/main/res/layout/activity_login.xml
@@ -13,15 +13,15 @@
diff --git a/sample-videochat-kotlin/app/src/main/res/layout/activity_settings.xml b/sample-videochat-kotlin/app/src/main/res/layout/activity_settings.xml
deleted file mode 100644
index 0e61fce29..000000000
--- a/sample-videochat-kotlin/app/src/main/res/layout/activity_settings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/res/layout/fragment_audio_conversation.xml b/sample-videochat-kotlin/app/src/main/res/layout/fragment_audio_conversation.xml
index 3b6d6afeb..9b5584f56 100644
--- a/sample-videochat-kotlin/app/src/main/res/layout/fragment_audio_conversation.xml
+++ b/sample-videochat-kotlin/app/src/main/res/layout/fragment_audio_conversation.xml
@@ -46,7 +46,7 @@
android:textSize="@dimen/also_on_call_text_size" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/res/layout/fragment_income_call.xml b/sample-videochat-kotlin/app/src/main/res/layout/fragment_income_call.xml
index dc380572a..8898bb141 100755
--- a/sample-videochat-kotlin/app/src/main/res/layout/fragment_income_call.xml
+++ b/sample-videochat-kotlin/app/src/main/res/layout/fragment_income_call.xml
@@ -61,7 +61,7 @@
android:textSize="@dimen/also_on_call_text_size" />
-
+
+
+
+
+
+
+ android:textSize="18sp"
+ android:textStyle="bold" />
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/res/layout/list_item_opponent_from_call.xml b/sample-videochat-kotlin/app/src/main/res/layout/list_item_opponent_from_call.xml
index f7c8bca2d..4dc7405e5 100644
--- a/sample-videochat-kotlin/app/src/main/res/layout/list_item_opponent_from_call.xml
+++ b/sample-videochat-kotlin/app/src/main/res/layout/list_item_opponent_from_call.xml
@@ -1,62 +1,58 @@
-
+ android:layout_height="match_parent"
+ android:layout_gravity="center">
-
+ android:layout_alignParentTop="true" />
-
+
-
-
-
+
-
-
+
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/res/layout/preference_version.xml b/sample-videochat-kotlin/app/src/main/res/layout/preference_version.xml
index f8f846465..24ab5c274 100644
--- a/sample-videochat-kotlin/app/src/main/res/layout/preference_version.xml
+++ b/sample-videochat-kotlin/app/src/main/res/layout/preference_version.xml
@@ -7,5 +7,4 @@
android:paddingTop="@dimen/margin_common"
android:paddingBottom="@dimen/margin_common"
android:text="@string/versionName"
- android:textSize="@dimen/text_size_ringing"
- android:textStyle="normal" />
\ No newline at end of file
+ android:textSize="@dimen/text_size_ringing" />
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/res/layout/toolbar_call.xml b/sample-videochat-kotlin/app/src/main/res/layout/toolbar_call.xml
index 364130ee7..85e52180a 100644
--- a/sample-videochat-kotlin/app/src/main/res/layout/toolbar_call.xml
+++ b/sample-videochat-kotlin/app/src/main/res/layout/toolbar_call.xml
@@ -14,7 +14,6 @@
android:id="@+id/timer_call"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
android:layout_margin="@dimen/margin_common"
android:textColor="@color/text_color_light_grey"
android:textSize="@dimen/text_size"
diff --git a/sample-videochat-kotlin/app/src/main/res/layout/view_outgoing_screen.xml b/sample-videochat-kotlin/app/src/main/res/layout/view_outgoing_screen.xml
index 72008eaf3..7b5263e61 100644
--- a/sample-videochat-kotlin/app/src/main/res/layout/view_outgoing_screen.xml
+++ b/sample-videochat-kotlin/app/src/main/res/layout/view_outgoing_screen.xml
@@ -16,7 +16,6 @@
android:paddingLeft="@dimen/padding_outgoing_screen"
android:paddingRight="@dimen/padding_outgoing_screen"
android:textSize="@dimen/text_size_call"
- android:textStyle="normal"
tools:text="John, Bob, Merlin" />
+ android:textSize="@dimen/text_size_ringing" />
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/res/menu/activity_opponents.xml b/sample-videochat-kotlin/app/src/main/res/menu/activity_opponents.xml
index 9f2765375..ca6aa0edb 100644
--- a/sample-videochat-kotlin/app/src/main/res/menu/activity_opponents.xml
+++ b/sample-videochat-kotlin/app/src/main/res/menu/activity_opponents.xml
@@ -10,11 +10,6 @@
app:showAsAction="always"
tools:ignore="AlwaysShowAction" />
-
-
- Rejected
Hung up
- disable_built_in_aec_preference
- false
-
- audioprocessing_preference
- false
-
- opensles_preference
- false
-
- hwcodec_preference
- true
-
- videocodec_preference
-
- %1$s must contain 3 —
- %2$s alphanumeric Latin characters without spaces, the first char must be a letter
-
- User name
- User Full Name
-
- 0
- 1
+ Use your email or alphanumeric characters in a range from 3 to 50. First character must be a letter.
+ Use alphanumeric characters and spaces in a range from 3 to 20. Cannot contain more than one space in a row.
v %s
- User full name
+ Display name
Enter to chat
Please enter username and chat room name. \nYou can join existed chat room.
- User login
+ Login
Select dialog you want to join
@@ -64,49 +44,6 @@
%s (you)
Please, choose at least one participant
-
- Video
- Call Settings
-
- Video codec hardware acceleration
- Disable built-in AEC
- Disable built-in AEC
- Use OpenSL ES for audio playback
- Use OpenSL ES for audio playback
- Disable audio processing pipeline
- Disable audio processing
-
-
- resolution_preference
- Video Format
- Enter RTC local video resolution
- -1
-
- startbitratevalue_preference
- Bandwidth (0–2000)
- 0
- 0
- 2000
- 100
-
- frame_rate
- Frame Rate (0–30)
- 0
- 0
- 30
- 5
-
- pref_audio_codec
- Default audio codec
- ISAC
- Select default audio codec
-
- 0
- Select default video codec
- Default video codec
-
- Packet loss occurs
-
"%s is calling you"
@@ -154,29 +91,14 @@
%s dialog selected
%s dialogs selected
-
- manage_speakerphone_by_proximity_preference
- false
-
-
- answer_time_interval
- 30
- disconnect_time_interval
- 10
- Dialing_time_interval
- 5
-
+
Also on call:
-
User 1, User 2, User 3, User 4, User 5, User 6
-
Connection was lost
-
and %s
-
Accepted
-
Stop
+ You
Application version:
@@ -216,5 +138,4 @@
You should allow Camera permission
You should allow Microphone permission
Error getting permissions
-
\ No newline at end of file
diff --git a/sample-videochat-kotlin/app/src/main/res/xml/preferences.xml b/sample-videochat-kotlin/app/src/main/res/xml/preferences.xml
deleted file mode 100644
index 9fe629e4a..000000000
--- a/sample-videochat-kotlin/app/src/main/res/xml/preferences.xml
+++ /dev/null
@@ -1,86 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/sample-videochat-kotlin/build.gradle b/sample-videochat-kotlin/build.gradle
index cbe1ad7e0..370971703 100644
--- a/sample-videochat-kotlin/build.gradle
+++ b/sample-videochat-kotlin/build.gradle
@@ -6,7 +6,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:4.2.2'
- classpath 'com.google.gms:google-services:4.3.10'
+ classpath 'com.google.gms:google-services:4.3.13'
}
}
@@ -15,30 +15,4 @@ allprojects {
google()
mavenCentral()
}
-}
-
-ext {
- dimensionDefault = 'default'
-
- lintAbortOnError = false
-
- // QuickBlox SDK version
- qbSdkVersion = '3.9.15'
-
- //Firebase
- firebaseCoreVersion = '20.1.2'
-
- //Material
- materialVersion = '1.5.0'
-
- //RobotoTextView
- robotoTextViewVersion = '4.0.0'
-
- //Android X
- fragmentAndroidXVersion = '1.4.1'
- lifecycleViewmodelAndroidXVersion = '2.4.1'
- coreKtxVersion = '1.7.0'
-
- //Kotlin
- kotlinGradlePluginVersion = '1.5.31'
}
\ No newline at end of file
diff --git a/sample-videochat-kotlin/gradle/wrapper/gradle-wrapper.properties b/sample-videochat-kotlin/gradle/wrapper/gradle-wrapper.properties
index 4d9ca1649..8a2b5de27 100644
--- a/sample-videochat-kotlin/gradle/wrapper/gradle-wrapper.properties
+++ b/sample-videochat-kotlin/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,6 @@
+#Mon Jul 25 15:08:47 CEST 2022
distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
-zipStoreBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
diff --git a/sample-videochat-kotlin/proguard-rules.pro b/sample-videochat-kotlin/proguard-rules.pro
deleted file mode 100755
index f1dd7da4b..000000000
--- a/sample-videochat-kotlin/proguard-rules.pro
+++ /dev/null
@@ -1,70 +0,0 @@
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in /home/tereha/Android/sdk/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the proguardFiles
-# directive in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-#-dontusemixedcaseclassnames
-#-dontskipnonpubliclibraryclasses
-#-verbose
-#
-
-##---------------Begin: proguard configuration for Gson ----------
-# Gson uses generic type information stored in a class file when working with fields. Proguard
-# removes such information by default, so configure it to keep all of it.
--keepattributes Signature
-
-# For using GSON @Expose annotation
--keepattributes *Annotation*
-
-# Gson specific classes
--keep class sun.misc.Unsafe { *; }
-#-keep class com.google.gson.stream.** { *; }
-
-# Application classes that will be serialized/deserialized over Gson
- -keep class com.quickblox.core.account.model.** { *; }
-
-
-##---------------End: proguard configuration for Gson ----------
-#quickblox sample chat
-
--keep class com.quickblox.auth.parsers.** { *; }
--keep class com.quickblox.auth.model.** { *; }
--keep class com.quickblox.core.parser.** { *; }
--keep class com.quickblox.core.model.** { *; }
--keep class com.quickblox.core.server.** { *; }
--keep class com.quickblox.core.rest.** { *; }
--keep class com.quickblox.core.error.** { *; }
--keep class com.quickblox.core.Query { *; }
-
--keep class com.quickblox.users.parsers.** { *; }
--keep class com.quickblox.users.model.** { *; }
-
--keep class com.quickblox.chat.parser.** { *; }
--keep class com.quickblox.chat.model.** { *; }
-
--keep class com.quickblox.messages.parsers.** { *; }
--keep class com.quickblox.messages.model.** { *; }
-
--keep class com.quickblox.content.parsers.** { *; }
--keep class com.quickblox.content.model.** { *; }
-
--keep class org.jivesoftware.** { *; }
-
-#sample chat
--keep class android.support.v7.** { *; }
--keep class com.bumptech.** { *; }
-
--dontwarn org.jivesoftware.smackx.**
--dontwarn android.support.v4.app.**
\ No newline at end of file