diff --git a/sample-videochat-kotlin/app/build.gradle b/sample-videochat-kotlin/app/build.gradle
index 6d6d3bdf8..3d08a2c63 100644
--- a/sample-videochat-kotlin/app/build.gradle
+++ b/sample-videochat-kotlin/app/build.gradle
@@ -1,19 +1,16 @@
buildscript {
repositories {
google()
- jcenter()
- maven { url 'https://maven.fabric.io/public' }
+ mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinGradlePluginVersion"
- classpath "io.fabric.tools:gradle:$fabricToolsVersion"
}
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
-apply plugin: 'io.fabric'
androidExtensions {
experimental = true
@@ -21,27 +18,25 @@ androidExtensions {
repositories {
google()
- jcenter()
+ mavenCentral()
maven {
url "https://github.com/QuickBlox/quickblox-android-sdk-releases/raw/master/"
}
- maven { url 'https://maven.fabric.io/public' }
- flatDir { dirs 'libs' }
}
android {
- def versionQACode = 3
+ def versionQACode = 1
- compileSdkVersion 28
- buildToolsVersion "28.0.3"
+ compileSdkVersion 31
+ buildToolsVersion "31.0.0"
flavorDimensions dimensionDefault
defaultConfig {
applicationId "com.quickblox.sample.videochat.kotlin"
- minSdkVersion 16
- targetSdkVersion 28
- versionCode 404000
- versionName '4.0.4'
+ minSdkVersion 21
+ targetSdkVersion 31
+ versionCode 405000
+ versionName '4.0.5'
multiDexEnabled true
}
@@ -65,12 +60,14 @@ android {
minifyEnabled false
shrinkResources false
proguardFile 'proguard-rules.pro'
- zipAlignEnabled false
resValue "string", "versionName", "QuickBlox Video Chat Kotlin\nBuild version " + defaultConfig.getVersionName()
}
release {
signingConfig signingConfigs.debug
+ minifyEnabled true
+ shrinkResources true
+ proguardFile 'proguard-rules.pro'
resValue "string", "versionName", "QuickBlox Video Chat Kotlin\nBuild version " + defaultConfig.getVersionName()
}
}
@@ -95,21 +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.github.bumptech.glide:glide:$glideVersion"
implementation "com.google.android.material:material:$materialVersion"
implementation "com.github.johnkil.android-robototextview:robototextview:$robotoTextViewVersion"
- implementation "androidx.fragment:fragment:$fragmentAndroidXVersion"
- implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycleViewmodelAndroidXVersion"
+ implementation "androidx.fragment:fragment-ktx:$fragmentAndroidXVersion"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleViewmodelAndroidXVersion"
implementation "androidx.core:core-ktx:$coreKtxVersion"
- implementation("com.crashlytics.sdk.android:crashlytics:$crashlyticsVersion@aar") {
- transitive = true
- }
- compile "org.jetbrains.kotlin:kotlin-reflect:$kotlinReflectVersion"
}
apply from: "../artifacts.gradle"
diff --git a/sample-videochat-kotlin/app/google-services.json b/sample-videochat-kotlin/app/google-services.json
index 542e3ac38..97ec23e8e 100644
--- a/sample-videochat-kotlin/app/google-services.json
+++ b/sample-videochat-kotlin/app/google-services.json
@@ -1,154 +1,29 @@
{
"project_info": {
- "project_number": "247738611464",
- "firebase_url": "https://qb-prod-samples.firebaseio.com",
- "project_id": "qb-prod-samples",
- "storage_bucket": "qb-prod-samples.appspot.com"
+ "project_number": "Put here your value",
+ "firebase_url": "https://qb-samples.firebaseio.com",
+ "project_id": "qb-samples",
+ "storage_bucket": "qb-samples.appspot.com"
},
"client": [
{
"client_info": {
- "mobilesdk_app_id": "1:247738611464:android:beb270faa2c3a789",
+ "mobilesdk_app_id": "Put here your value",
"android_client_info": {
- "package_name": "com.quickblox.sample.chat.java"
- }
- },
- "oauth_client": [],
- "api_key": [
- {
- "current_key": "AIzaSyBFXAfVr6kkFJdDNOm8U-c7iju0qIUkc_A"
- }
- ],
- "services": {
- "appinvite_service": {
- "other_platform_oauth_client": [
- {
- "client_id": "247738611464-v2nvd29bmqum7niosnfuh28oq3beh9f6.apps.googleusercontent.com",
- "client_type": 3
- }
- ]
- }
- }
- },
- {
- "client_info": {
- "mobilesdk_app_id": "1:247738611464:android:1cdc72e9ffd29448",
- "android_client_info": {
- "package_name": "com.quickblox.sample.chat.kotlin"
- }
- },
- "oauth_client": [],
- "api_key": [
- {
- "current_key": "AIzaSyBFXAfVr6kkFJdDNOm8U-c7iju0qIUkc_A"
- }
- ],
- "services": {
- "appinvite_service": {
- "other_platform_oauth_client": [
- {
- "client_id": "247738611464-v2nvd29bmqum7niosnfuh28oq3beh9f6.apps.googleusercontent.com",
- "client_type": 3
- }
- ]
- }
- }
- },
- {
- "client_info": {
- "mobilesdk_app_id": "1:247738611464:android:06cb0de4c719ad84",
- "android_client_info": {
- "package_name": "com.quickblox.sample.pushnotifications.java"
- }
- },
- "oauth_client": [],
- "api_key": [
- {
- "current_key": "AIzaSyBFXAfVr6kkFJdDNOm8U-c7iju0qIUkc_A"
- }
- ],
- "services": {
- "appinvite_service": {
- "other_platform_oauth_client": [
- {
- "client_id": "247738611464-v2nvd29bmqum7niosnfuh28oq3beh9f6.apps.googleusercontent.com",
- "client_type": 3
- }
- ]
- }
- }
- },
- {
- "client_info": {
- "mobilesdk_app_id": "1:247738611464:android:c2749661061637f0",
- "android_client_info": {
- "package_name": "com.quickblox.sample.pushnotifications.kotlin"
- }
- },
- "oauth_client": [],
- "api_key": [
- {
- "current_key": "AIzaSyBFXAfVr6kkFJdDNOm8U-c7iju0qIUkc_A"
- }
- ],
- "services": {
- "appinvite_service": {
- "other_platform_oauth_client": [
- {
- "client_id": "247738611464-v2nvd29bmqum7niosnfuh28oq3beh9f6.apps.googleusercontent.com",
- "client_type": 3
- }
- ]
- }
- }
- },
- {
- "client_info": {
- "mobilesdk_app_id": "1:247738611464:android:99e5b55a490c901c",
- "android_client_info": {
- "package_name": "com.quickblox.sample.videochat.java"
+ "package_name": "com.quickblox.sample.videochat.kotlin"
}
},
- "oauth_client": [],
- "api_key": [
+ "oauth_client": [
{
- "current_key": "AIzaSyBFXAfVr6kkFJdDNOm8U-c7iju0qIUkc_A"
+ "client_id": "Put here your value",
+ "client_type": 3
}
],
- "services": {
- "appinvite_service": {
- "other_platform_oauth_client": [
- {
- "client_id": "247738611464-v2nvd29bmqum7niosnfuh28oq3beh9f6.apps.googleusercontent.com",
- "client_type": 3
- }
- ]
- }
- }
- },
- {
- "client_info": {
- "mobilesdk_app_id": "1:247738611464:android:ac22e0d1b3a3e86b",
- "android_client_info": {
- "package_name": "com.quickblox.sample.videochat.kotlin"
- }
- },
- "oauth_client": [],
"api_key": [
{
- "current_key": "AIzaSyBFXAfVr6kkFJdDNOm8U-c7iju0qIUkc_A"
- }
- ],
- "services": {
- "appinvite_service": {
- "other_platform_oauth_client": [
- {
- "client_id": "247738611464-v2nvd29bmqum7niosnfuh28oq3beh9f6.apps.googleusercontent.com",
- "client_type": 3
- }
- ]
+ "current_key": "Put here your value"
}
- }
+ ]
}
],
"configuration_version": "1"
diff --git a/sample-videochat-kotlin/app/proguard-rules.pro b/sample-videochat-kotlin/app/proguard-rules.pro
index f1b424510..7c835c9ff 100644
--- a/sample-videochat-kotlin/app/proguard-rules.pro
+++ b/sample-videochat-kotlin/app/proguard-rules.pro
@@ -1,6 +1,8 @@
# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
+# 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
@@ -11,11 +13,32 @@
#-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 EnclosingMethod
+-keepattributes InnerClasses
+-keepattributes Signature
+-keepattributes Exceptions
+
+# For using GSON @Expose annotation
+-keepattributes *Annotation*
+
+#quickblox sdk
+-keep class com.quickblox.** { *; }
+
+#smack xmpp library
+-keep class org.jxmpp.** { *; }
+-keep class org.jivesoftware.** { *; }
+-dontwarn org.jivesoftware.**
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
+#webrtc
+-keep class org.webrtc.** { *; }
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
+#google gms
+-keep class com.google.android.gms.** { *; }
\ 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 b271a0c97..1f9e4169f 100644
--- a/sample-videochat-kotlin/app/src/main/AndroidManifest.xml
+++ b/sample-videochat-kotlin/app/src/main/AndroidManifest.xml
@@ -3,7 +3,6 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.quickblox.sample.videochat.kotlin">
-
@@ -12,7 +11,7 @@
-
+
@@ -64,15 +64,21 @@
-
+
-
+
-
+
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 3de0ac38d..81bd0a966 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
@@ -1,10 +1,8 @@
package com.quickblox.sample.videochat.kotlin
import android.app.Application
-import com.crashlytics.android.Crashlytics
import com.quickblox.auth.session.QBSettings
import com.quickblox.sample.videochat.kotlin.db.DbHelper
-import io.fabric.sdk.android.Fabric
//User default credentials
const val DEFAULT_USER_PASSWORD = "quickblox"
@@ -30,17 +28,10 @@ class App : Application() {
super.onCreate()
instance = this
dbHelper = DbHelper(this)
- initFabric()
checkCredentials()
initCredentials()
}
- private fun initFabric() {
- if (!BuildConfig.DEBUG) {
- Fabric.with(this, Crashlytics())
- }
- }
-
private fun checkCredentials() {
if (APPLICATION_ID.isEmpty() || AUTH_KEY.isEmpty() || AUTH_SECRET.isEmpty() || ACCOUNT_KEY.isEmpty()) {
throw AssertionError(getString(R.string.error_qb_credentials_empty))
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 98f403eef..626995549 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
@@ -75,8 +75,8 @@ class AppInfoActivity : AppCompatActivity() {
}
}
- override fun onOptionsItemSelected(item: MenuItem?): Boolean {
- when (item?.itemId) {
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ when (item.itemId) {
android.R.id.home -> {
finish()
return true
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 e3f42bc5d..a6a88b1a3 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
@@ -36,7 +36,7 @@ abstract class BaseActivity : AppCompatActivity() {
}
internal fun hideProgressDialog() {
- if (progressDialog != null && progressDialog!!.isShowing) {
+ if (progressDialog != null && progressDialog?.isShowing == true) {
progressDialog!!.dismiss()
}
}
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 292f66abf..54197eaae 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
@@ -19,6 +19,7 @@ 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.utils.*
import com.quickblox.users.model.QBUser
@@ -31,7 +32,7 @@ import com.quickblox.videochat.webrtc.view.QBRTCVideoTrack
import org.jivesoftware.smack.AbstractConnectionListener
import org.jivesoftware.smack.ConnectionListener
import org.webrtc.CameraVideoCapturer
-import java.util.HashMap
+import java.util.*
import kotlin.collections.ArrayList
private const val INCOME_CALL_FRAGMENT = "income_call_fragment"
@@ -265,17 +266,9 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
}
private fun initIncomingCallTask() {
- showIncomingCallWindowTaskHandler = Handler(Looper.myLooper())
+ showIncomingCallWindowTaskHandler = Handler(Looper.getMainLooper())
showIncomingCallWindowTask = Runnable {
if (callService.currentSessionExist()) {
- /*val currentSessionState = callService.getCurrentSessionState()
- if (BaseSession.QBRTCSessionState.QB_RTC_SESSION_NEW == currentSessionState) {
- callService.rejectCurrentSession(HashMap())
- } else {
- callService.stopRingtone()
- hangUpCurrentSession()
- }*/
- // This is a fix to prevent call stop in case calling to user with more then one device logged in.
longToast("Call was stopped by UserNoActions timer")
callService.clearCallState()
callService.clearButtonsState()
@@ -316,14 +309,14 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
}
override fun finish() {
- //Fix bug when user returns to call from service and the backstack doesn't have any screens
+ // fix bug when user returns to call from service and the backstack doesn't have any screens
OpponentsActivity.start(this)
CallService.stop(this)
super.finish()
}
override fun onBackPressed() {
- // To prevent returning from Call Fragment
+ // to prevent returning from Call Fragment
}
private fun addIncomeCallFragment() {
@@ -366,8 +359,6 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
}
}
- ////////////////////////////// ConnectionListener //////////////////////////////
-
private inner class ConnectionListenerImpl : AbstractConnectionListener() {
override fun connectionClosedOnError(e: Exception?) {
showNotificationPopUp(R.string.connection_was_lost, true)
@@ -378,10 +369,8 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
}
}
- ////////////////////////////// QBRTCSessionStateCallbackListener ///////////////////////////
-
override fun onDisconnectedFromUser(session: QBRTCSession?, userId: Int?) {
-
+ // empty
}
override fun onConnectedToUser(session: QBRTCSession?, userId: Int?) {
@@ -393,15 +382,13 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
}
override fun onConnectionClosedForUser(session: QBRTCSession?, userId: Int?) {
-
+ // empty
}
override fun onStateChanged(session: QBRTCSession?, sessiontState: BaseSession.QBRTCSessionState?) {
-
+ // empty
}
- ////////////////////////////// QBRTCClientSessionCallbacks //////////////////////////////
-
override fun onUserNotAnswer(session: QBRTCSession?, userId: Int?) {
if (callService.isCurrentSession(session)) {
callService.stopRingtone()
@@ -417,9 +404,9 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
override fun onReceiveHangUpFromUser(session: QBRTCSession?, userId: Int?, map: MutableMap?) {
if (callService.isCurrentSession(session)) {
- if (userId == session?.callerID) {
+ val numberOpponents = session?.opponents?.size
+ if (numberOpponents == ONE_OPPONENT) {
hangUpCurrentSession()
- Log.d(TAG, "initiator hung up the call")
}
val participant = QbUsersDbManager.getUserById(userId)
val participantName = if (participant != null) participant.fullName else userId.toString()
@@ -434,7 +421,7 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
}
override fun onReceiveNewSession(session: QBRTCSession?) {
-
+ // empty
}
override fun onUserNoActions(session: QBRTCSession?, userId: Int?) {
@@ -454,8 +441,6 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
}
}
- ////////////////////////////// IncomeCallFragmentCallbackListener ////////////////////////////
-
override fun onAcceptCurrentSession() {
if (callService.currentSessionExist()) {
addConversationFragment(true)
@@ -468,8 +453,6 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
callService.rejectCurrentSession(HashMap())
}
- ////////////////////////////// ConversationFragmentCallback ////////////////////////////
-
override fun addConnectionListener(connectionCallback: ConnectionListener?) {
callService.addConnectionListener(connectionCallback)
}
@@ -533,9 +516,11 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
}
override fun addOnChangeAudioDeviceListener(onChangeDynamicCallback: OnChangeAudioDevice?) {
+ // empty
}
override fun removeOnChangeAudioDeviceListener(onChangeDynamicCallback: OnChangeAudioDevice?) {
+ // empty
}
override fun acceptCall(userInfo: Map) {
@@ -621,14 +606,14 @@ class CallActivity : BaseActivity(), IncomeCallFragmentCallbackListener, QBRTCSe
private inner class CallServiceConnection : ServiceConnection {
override fun onServiceDisconnected(name: ComponentName?) {
-
+ // empty
}
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
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
+ // we have already currentSession == null, so it's no reason to do further initialization
if (QBChatService.getInstance().isLoggedIn) {
initScreen()
} else {
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 ba59192f0..15f9d8a4b 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
@@ -29,7 +29,8 @@ class LoginActivity : BaseActivity() {
private lateinit var user: QBUser
companion object {
- fun start(context: Context) = context.startActivity(Intent(context, LoginActivity::class.java))
+ fun start(context: Context) =
+ context.startActivity(Intent(context, LoginActivity::class.java))
}
override fun onCreate(savedInstanceState: Bundle?) {
@@ -125,7 +126,7 @@ class LoginActivity : BaseActivity() {
isLoginSuccess = it.getBooleanExtra(EXTRA_LOGIN_RESULT, false)
}
- var errorMessage = getString(R.string.unknown_error)
+ var errorMessage: String? = getString(R.string.unknown_error)
data?.let {
errorMessage = it.getStringExtra(EXTRA_LOGIN_ERROR_MESSAGE)
}
@@ -181,7 +182,8 @@ class LoginActivity : BaseActivity() {
LoginService.start(this, qbUser, pendingIntent)
}
- private inner class LoginEditTextWatcher internal constructor(private val editText: EditText) : TextWatcher {
+ private inner class LoginEditTextWatcher internal constructor(private val editText: EditText) :
+ TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
diff --git a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/PermissionsActivity.kt b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/PermissionsActivity.kt
index ebd46d0ae..3c9c5cdde 100644
--- a/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/PermissionsActivity.kt
+++ b/sample-videochat-kotlin/app/src/main/java/com/quickblox/sample/videochat/kotlin/activities/PermissionsActivity.kt
@@ -34,9 +34,6 @@ class PermissionsActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- if (intent == null || !intent.hasExtra(EXTRA_PERMISSIONS)) {
- throw RuntimeException("This Activity needs to be launched using the static startActivityForResult() method.")
- }
setContentView(R.layout.activity_permissions)
supportActionBar?.hide()
requiresCheck = true
@@ -44,6 +41,10 @@ class PermissionsActivity : BaseActivity() {
override fun onResume() {
super.onResume()
+ if (intent == null || !intent.hasExtra(EXTRA_PERMISSIONS)) {
+ throw RuntimeException("This Activity needs to be launched using the static startActivityForResult() method.")
+ }
+
if (requiresCheck) {
checkPermissions()
} else {
@@ -52,8 +53,9 @@ class PermissionsActivity : BaseActivity() {
}
private fun checkPermissions() {
- val permissions = getPermissions()
- val checkOnlyAudio = getCheckOnlyAudio()
+ val permissions = intent.getStringArrayExtra(EXTRA_PERMISSIONS)!!
+
+ val checkOnlyAudio = intent.getBooleanExtra(CHECK_ONLY_AUDIO, false)
if (checkOnlyAudio) {
checkPermissionAudio(permissions[1])
@@ -78,14 +80,6 @@ class PermissionsActivity : BaseActivity() {
}
}
- private fun getPermissions(): Array {
- return intent.getStringArrayExtra(EXTRA_PERMISSIONS)
- }
-
- private fun getCheckOnlyAudio(): Boolean {
- return intent.getBooleanExtra(CHECK_ONLY_AUDIO, false)
- }
-
private fun requestPermissions(vararg permissions: String) {
ActivityCompat.requestPermissions(this, permissions, PERMISSION_CODE)
}
@@ -96,6 +90,7 @@ class PermissionsActivity : BaseActivity() {
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == PERMISSION_CODE && hasAllPermissionsGranted(grantResults)) {
requiresCheck = true
allPermissionsGranted()
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 c3b398b5a..9707db697 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
@@ -1,6 +1,7 @@
package com.quickblox.sample.videochat.kotlin.fragments
import android.app.Activity
+import android.content.Context
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
@@ -50,8 +51,8 @@ abstract class BaseConversationFragment : BaseToolBarFragment(), CallActivity.Cu
}
}
- override fun onAttach(activity: Activity?) {
- super.onAttach(activity)
+ override fun onAttach(context: Context) {
+ super.onAttach(context)
try {
conversationFragmentCallback = context as ConversationFragmentCallback
} catch (e: ClassCastException) {
@@ -191,7 +192,6 @@ abstract class BaseConversationFragment : BaseToolBarFragment(), CallActivity.Cu
}
override fun onCallStopped() {
- CallService.stop(activity as Activity)
isStarted = false
clearButtonsState()
actionButtonsEnabled(false)
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 707f6ec36..e12090bc9 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
@@ -60,8 +60,8 @@ class IncomeCallFragment : Fragment(), Serializable, View.OnClickListener {
private lateinit var incomeCallFragmentCallbackListener: IncomeCallFragmentCallbackListener
private var currentSession: QBRTCSession? = null
- override fun onAttach(activity: Activity?) {
- super.onAttach(activity)
+ override fun onAttach(context: Context) {
+ super.onAttach(context)
try {
incomeCallFragmentCallbackListener = activity as IncomeCallFragmentCallbackListener
} catch (e: ClassCastException) {
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 14c31b893..66d56f8ff 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
@@ -6,10 +6,8 @@ import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.fragment.app.Fragment
-import com.bumptech.glide.Glide
-import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.quickblox.sample.videochat.kotlin.R
-import com.quickblox.sample.videochat.kotlin.utils.getDimen
+import com.quickblox.sample.videochat.kotlin.utils.getDrawable
private const val PREVIEW_IMAGE = "preview_image"
@@ -27,11 +25,13 @@ 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)
- Glide.with(activity)
- .load(arguments?.getInt(PREVIEW_IMAGE))
- .diskCacheStrategy(DiskCacheStrategy.ALL)
- .override(getDimen(R.dimen.pager_image_width), getDimen(R.dimen.pager_image_height))
- .into(view.findViewById(R.id.image_preview) as ImageView)
+
+ val ivPreview = view.findViewById(R.id.image_preview)
+ val imageDrawable = arguments?.getInt(PREVIEW_IMAGE)
+
+ imageDrawable?.let {
+ ivPreview.setImageDrawable(getDrawable(it))
+ }
return view
}
}
\ No newline at end of file
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 b8788e955..dfa07de19 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
@@ -48,13 +48,13 @@ class ScreenShareFragment : BaseToolBarFragment() {
(activity as CallActivity).addCurrentCallStateListener(currentCallStateCallback!!)
}
- override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
- inflater?.inflate(R.menu.screen_share_fragment, menu)
+ override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
+ inflater.inflate(R.menu.screen_share_fragment, menu)
super.onCreateOptionsMenu(menu, inflater)
}
- override fun onOptionsItemSelected(item: MenuItem?): Boolean {
- when (item?.itemId) {
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ when (item.itemId) {
R.id.stop_screen_share -> {
Log.d(TAG, "stop_screen_share")
onSharingEvents?.onStopPreview()
@@ -64,7 +64,7 @@ class ScreenShareFragment : BaseToolBarFragment() {
}
}
- override fun onAttach(context: Context?) {
+ override fun onAttach(context: Context) {
super.onAttach(context)
try {
onSharingEvents = context as OnSharingEvents?
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 b5747142a..f5514ac0b 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
@@ -1,6 +1,5 @@
package com.quickblox.sample.videochat.kotlin.fragments
-import android.app.Activity
import android.content.Context
import android.graphics.Color
import android.graphics.Rect
@@ -18,8 +17,9 @@ import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.quickblox.sample.videochat.kotlin.R
+import com.quickblox.sample.videochat.kotlin.activities.CallActivity
import com.quickblox.sample.videochat.kotlin.adapters.OpponentsFromCallAdapter
-import com.quickblox.sample.videochat.kotlin.services.CallService
+import com.quickblox.sample.videochat.kotlin.db.QbUsersDbManager
import com.quickblox.sample.videochat.kotlin.utils.SharedPrefsHelper
import com.quickblox.sample.videochat.kotlin.utils.shortToast
import com.quickblox.users.model.QBUser
@@ -50,13 +50,12 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
OpponentsFromCallAdapter.OnAdapterEventListener {
private val TAG = VideoConversationFragment::class.java.simpleName
- //Views
private lateinit var cameraToggle: ToggleButton
private var parentView: View? = null
private lateinit var actionVideoButtonsLayout: LinearLayout
private lateinit var connectionStatusLocal: TextView
private lateinit var recyclerView: RecyclerView
- private lateinit var localVideoView: QBRTCSurfaceView
+ private var localVideoView: QBRTCSurfaceView? = null
private var remoteFullScreenVideoView: QBRTCSurfaceView? = null
private lateinit var opponentViewHolders: SparseArray
@@ -74,90 +73,49 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
private var isCurrentCameraFront: Boolean = false
private var isLocalVideoFullScreen: Boolean = false
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- parentView = super.onCreateView(inflater, container, savedInstanceState)
- return parentView
- }
-
- 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))
- }
-
- override fun configureActionBar() {
- actionBar.setDisplayShowTitleEnabled(false)
- }
-
- 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))
- }
-
override fun getFragmentLayout(): Int {
return R.layout.fragment_video_conversation
}
- override fun initFields() {
- super.initFields()
- localViewOnClickListener = LocalViewOnClickListener()
- amountOpponents = opponents.size
- allOpponents = Collections.synchronizedList(ArrayList(opponents.size))
- allOpponents.addAll(opponents)
-
- timerCallText = activity!!.findViewById(R.id.timer_call)
-
- isPeerToPeerCall = opponents.size == 1
- }
-
- private fun setDuringCallActionBar() {
- actionBar.setDisplayShowTitleEnabled(true)
- actionBar.title = currentUser.fullName
- if (isPeerToPeerCall) {
- actionBar.subtitle = getString(R.string.opponent, opponents[0].fullName)
- } else {
- actionBar.subtitle = getString(R.string.opponents, amountOpponents.toString())
- }
-
- actionButtonsEnabled(true)
- }
-
- private fun addListeners() {
- conversationFragmentCallback?.addSessionStateListener(this)
- conversationFragmentCallback?.addSessionEventsListener(this)
- conversationFragmentCallback?.addVideoTrackListener(this)
- }
-
- private fun removeListeners() {
- conversationFragmentCallback?.removeSessionStateListener(this)
- conversationFragmentCallback?.removeSessionEventsListener(this)
- conversationFragmentCallback?.removeVideoTrackListener(this)
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setHasOptionsMenu(true)
}
- override fun actionButtonsEnabled(inability: Boolean) {
- super.actionButtonsEnabled(inability)
- cameraToggle.isEnabled = inability
- // inactivate toggle buttons
- cameraToggle.isActivated = inability
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ parentView = super.onCreateView(inflater, container, savedInstanceState)
+ return parentView
}
override fun onStart() {
super.onStart()
- Log.i(TAG, "onStart")
if (!allCallbacksInit) {
addListeners()
allCallbacksInit = true
}
}
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- Log.i(TAG, "onCreate")
- setHasOptionsMenu(true)
+ override fun onResume() {
+ super.onResume()
+ toggleCamera(cameraToggle.isChecked)
+ }
+
+ override fun onPause() {
+ // if camera state is CameraState.ENABLED_FROM_USER or CameraState.NONE
+ // than we turn off cam
+ toggleCamera(false)
+
+ if (connectionEstablished) {
+ allCallbacksInit = false
+ } else {
+ Log.d(TAG, "We are in dialing process yet!")
+ }
+
+ releaseViewHolders()
+ removeListeners()
+ releaseViews()
+
+ super.onPause()
}
override fun initViews(view: View?) {
@@ -171,7 +129,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
isCurrentCameraFront = true
localVideoView = view.findViewById(R.id.local_video_view)
initCorrectSizeForLocalView()
- localVideoView.setZOrderMediaOverlay(true)
+ localVideoView?.setZOrderMediaOverlay(true)
remoteFullScreenVideoView = view.findViewById(R.id.remote_video_view)
remoteFullScreenVideoView?.setOnClickListener(localViewOnClickListener)
@@ -183,10 +141,10 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
recyclerView.addItemDecoration(DividerItemDecoration(context, R.dimen.grid_item_divider))
recyclerView.setHasFixedSize(true)
val columnsCount = defineColumnsCount()
- val layoutManager = LinearLayoutManager(activity, LinearLayout.HORIZONTAL, false)
+ val layoutManager = LinearLayoutManager(activity, RecyclerView.HORIZONTAL, false)
recyclerView.layoutManager = layoutManager
- //for correct removing item in adapter
+ // for correct removing item in adapter
recyclerView.itemAnimator = null
recyclerView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
@@ -212,6 +170,68 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
restoreSession()
}
+ override fun initFields() {
+ super.initFields()
+ localViewOnClickListener = LocalViewOnClickListener()
+ amountOpponents = opponents.size
+ allOpponents = Collections.synchronizedList(ArrayList(opponents.size))
+ allOpponents.addAll(opponents)
+
+ timerCallText = activity!!.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))
+ }
+
+ override fun configureActionBar() {
+ actionBar.setDisplayShowTitleEnabled(false)
+ }
+
+ 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))
+ }
+
+ private fun setDuringCallActionBar() {
+ actionBar.setDisplayShowTitleEnabled(true)
+ actionBar.title = currentUser.fullName
+ if (isPeerToPeerCall) {
+ actionBar.subtitle = getString(R.string.opponent, opponents[0].fullName)
+ } else {
+ actionBar.subtitle = getString(R.string.opponents, amountOpponents.toString())
+ }
+
+ actionButtonsEnabled(true)
+ }
+
+ private fun addListeners() {
+ conversationFragmentCallback?.addSessionStateListener(this)
+ conversationFragmentCallback?.addSessionEventsListener(this)
+ conversationFragmentCallback?.addVideoTrackListener(this)
+ }
+
+ private fun removeListeners() {
+ conversationFragmentCallback?.removeSessionStateListener(this)
+ conversationFragmentCallback?.removeSessionEventsListener(this)
+ conversationFragmentCallback?.removeVideoTrackListener(this)
+ }
+
+ override fun actionButtonsEnabled(inability: Boolean) {
+ super.actionButtonsEnabled(inability)
+ cameraToggle.isEnabled = inability
+ // inactivate toggle buttons
+ cameraToggle.isActivated = inability
+ }
+
private fun restoreSession() {
Log.d(TAG, "restoreSession ")
if (conversationFragmentCallback?.isCallState() == false) {
@@ -246,7 +266,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
}
private fun initCorrectSizeForLocalView() {
- val params = localVideoView.layoutParams
+ val params = localVideoView?.layoutParams
val displaymetrics = resources.displayMetrics
val screenWidthPx = displaymetrics.widthPixels
@@ -256,7 +276,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
val height = width / 2 * 3
params?.width = width
params?.height = height
- localVideoView.layoutParams = params
+ localVideoView?.layoutParams = params
}
private fun setGrid(columnsCount: Int) {
@@ -282,42 +302,19 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
return opponents.size - 1
}
- override fun onResume() {
- super.onResume()
- Log.d(TAG, "onResume")
- toggleCamera(cameraToggle.isChecked)
- }
-
- override fun onPause() {
- // If camera state is CameraState.ENABLED_FROM_USER or CameraState.NONE
- // than we turn off cam
- toggleCamera(false)
-
- if (connectionEstablished) {
- allCallbacksInit = false
- } else {
- Log.d(TAG, "We are in dialing process yet!")
- }
-
- releaseViewHolders()
- removeListeners()
- releaseViews()
-
- super.onPause()
- }
-
- override fun onDetach() {
- super.onDetach()
- Log.d(TAG, "onDetach")
- }
-
private fun releaseViewHolders() {
opponentViewHolders.clear()
}
private fun releaseViews() {
- localVideoView.release()
+ if (conversationFragmentCallback?.getCurrentSessionState() != BaseSession.QBRTCSessionState.QB_RTC_SESSION_CLOSED) {
+ for (item in (activity as CallActivity).getVideoTrackMap()) {
+ val renderer = item.value.renderer
+ item.value.removeRenderer(renderer)
+ }
+ }
+ localVideoView?.release()
remoteFullScreenVideoView?.release()
remoteFullScreenVideoView = null
@@ -328,7 +325,6 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
override fun onCallStopped() {
super.onCallStopped()
- CallService.stop(activity as Activity)
Log.i(TAG, "onCallStopped")
}
@@ -397,7 +393,6 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
}
}
- //////////////////////////// callbacks from QBRTCClientVideoTracksCallbacks ///////////////////
override fun onLocalVideoTrackReceive(qbrtcSession: QBRTCSession?, videoTrack: QBRTCVideoTrack) {
Log.d(TAG, "onLocalVideoTrackReceive() run")
localVideoTrack = videoTrack
@@ -424,12 +419,9 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
}
}
}
- ///////////////////////////////////////// end ////////////////////////////////////////////
- //last opponent parentView is bind
override fun onBindLastViewHolder(holder: OpponentsFromCallAdapter.ViewHolder, position: Int) {
Log.i(TAG, "onBindLastViewHolder position=$position")
-
}
override fun onItemClick(position: Int) {
@@ -465,12 +457,12 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
}
private fun swapUsersFullscreenToPreview(userId: Int) {
- // get opponentVideoTrack - opponent's video track from recyclerView
+ // get opponentVideoTrack - opponent's video track from recyclerView
val videoTrackMap = conversationFragmentCallback?.getVideoTrackMap()
val opponentVideoTrack = videoTrackMap?.get(userId)
- // get mainVideoTrack - opponent's video track from full screen
+ // get mainVideoTrack - opponent's video track from full screen
val mainVideoTrack = videoTrackMap?.get(userIDFullScreen)
val remoteVideoView = findHolder(userId)?.getOpponentView()
@@ -503,6 +495,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
fillVideoView(remoteVideoView, videoTrack, true)
} else {
isRemoteShown = true
+ itemHolder.getOpponentView().release()
opponentsAdapter.removeItem(itemHolder.adapterPosition)
setDuringCallActionBar()
setRecyclerViewVisibleState()
@@ -562,7 +555,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
/**
* @param userId set userId if it from fullscreen videoTrack
*/
- private fun fillVideoView(videoView: QBRTCSurfaceView, videoTrack: QBRTCVideoTrack,
+ private fun fillVideoView(videoView: QBRTCSurfaceView?, videoTrack: QBRTCVideoTrack,
remoteRenderer: Boolean) {
videoTrack.removeRenderer(videoTrack.renderer)
videoTrack.addRenderer(videoView)
@@ -572,12 +565,12 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
Log.d(TAG, (if (remoteRenderer) "remote" else "local") + " Track is rendering")
}
- private fun updateVideoView(videoView: SurfaceViewRenderer, mirror: Boolean) {
+ private fun updateVideoView(videoView: SurfaceViewRenderer?, mirror: Boolean) {
val scalingType = RendererCommon.ScalingType.SCALE_ASPECT_FILL
Log.i(TAG, "updateVideoView mirror:$mirror, scalingType = $scalingType")
- videoView.setScalingType(scalingType)
- videoView.setMirror(mirror)
- videoView.requestLayout()
+ videoView?.setScalingType(scalingType)
+ videoView?.setMirror(mirror)
+ videoView?.requestLayout()
}
/**
@@ -623,7 +616,6 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
val holder = getViewHolderForOpponent(userId) ?: return
holder.getProgressBar().visibility = View.GONE
-
}
private fun setBackgroundOpponentView(userId: Int?) {
@@ -634,10 +626,8 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
}
}
- /////////////////////////////// QBRTCSessionConnectionCallbacks ///////////////////////////
-
override fun onStateChanged(qbrtcSession: QBRTCSession, qbrtcSessionState: BaseSession.QBRTCSessionState) {
-
+ // empty
}
override fun onConnectedToUser(qbrtcSession: QBRTCSession?, userId: Int) {
@@ -660,9 +650,6 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
setStatusForOpponent(integer, getString(R.string.text_status_disconnected))
}
- ////////////////////////////////// end //////////////////////////////////////////
-
- /////////////////// Callbacks from CallActivity.QBRTCSessionUserCallback //////////////////////
override fun onUserNotAnswer(session: QBRTCSession, userId: Int) {
setProgressBarForOpponentGone(userId)
setStatusForOpponent(userId, getString(R.string.text_status_no_answer))
@@ -688,40 +675,41 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
}
override fun onSessionClosed(session: QBRTCSession) {
-
+ // empty
}
- ////////////////////////////////// end //////////////////////////////////////////
-
private fun setAnotherUserToFullScreen() {
if (opponentsAdapter.opponents.isEmpty()) {
return
}
- val userId = opponentsAdapter.getItem(0)
- // get opponentVideoTrack - opponent's video track from recyclerView
- val opponentVideoTrack = conversationFragmentCallback?.getVideoTrack(userId) ?: return
+ for (user in opponents){
+ val videoTrack = conversationFragmentCallback?.getVideoTrack(user.id)
+ if (videoTrack != null){
+ val userFullScreen = QbUsersDbManager.getUserById(userIDFullScreen)
- remoteFullScreenVideoView?.let {
- fillVideoView(userId, it, opponentVideoTrack)
- Log.d(TAG, "fullscreen enabled")
- }
+ val itemHolder = findHolder(user.id)
+ itemHolder?.setUserId(userIDFullScreen)
+ itemHolder?.setUserName(userFullScreen?.fullName.toString())
+ itemHolder?.setStatus(getString(R.string.text_status_closed))
+ itemHolder?.getOpponentView()?.release()
- val itemHolder = findHolder(userId)
- if (itemHolder != null) {
- opponentsAdapter.removeItem(itemHolder.adapterPosition)
- itemHolder.getOpponentView().release()
- Log.d(TAG, "onConnectionClosedForUser opponentsAdapter.removeItem= $userId")
+ remoteFullScreenVideoView?.let {
+ fillVideoView(user.id, it, videoTrack)
+ Log.d(TAG, "fullscreen enabled")
+ }
+ return
+ }
}
}
- override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
- inflater?.inflate(R.menu.conversation_fragment, menu)
+ override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
+ inflater.inflate(R.menu.conversation_fragment, menu)
super.onCreateOptionsMenu(menu, inflater)
optionsMenu = menu
}
- override fun onOptionsItemSelected(item: MenuItem?): Boolean {
- when (item?.itemId) {
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ when (item.itemId) {
R.id.camera_switch -> {
Log.d("Conversation", "camera_switch")
switchCamera(item)
@@ -762,7 +750,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
}
private fun runUpdateUsersNames(newUsers: ArrayList) {
- //need delayed for synchronization with recycler parentView initialization
+ // need delayed for synchronization with recycler parentView initialization
mainHandler.postDelayed({
for (user in newUsers) {
Log.d(TAG, "runUpdateUsersNames. foreach, user = " + user.fullName)
@@ -804,7 +792,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
private fun hideToolBarAndButtons() {
actionBar.hide()
- localVideoView.visibility = View.INVISIBLE
+ localVideoView?.visibility = View.INVISIBLE
actionVideoButtonsLayout.visibility = View.GONE
if (!isPeerToPeerCall) {
shiftBottomListOpponents()
@@ -813,7 +801,7 @@ class VideoConversationFragment : BaseConversationFragment(), Serializable,
private fun showToolBarAndButtons() {
actionBar.show()
- localVideoView.visibility = View.VISIBLE
+ localVideoView?.visibility = View.VISIBLE
actionVideoButtonsLayout.visibility = View.VISIBLE
if (!isPeerToPeerCall) {
shiftMarginListOpponents()
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 d8bd27817..5c3595b69 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
@@ -36,17 +36,17 @@ import org.webrtc.CameraVideoCapturer
import java.util.*
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
class CallService : Service() {
private var TAG = CallService::class.java.simpleName
private val callServiceBinder: CallServiceBinder = CallServiceBinder()
- private var videoTrackMap: MutableMap = java.util.HashMap()
+ private var videoTrackMap: MutableMap = HashMap()
private lateinit var networkConnectionListener: NetworkConnectionListener
private lateinit var networkConnectionChecker: NetworkConnectionChecker
private lateinit var sessionEventsListener: SessionEventsListener
@@ -100,7 +100,6 @@ class CallService : Service() {
super.onDestroy()
networkConnectionChecker.unregisterListener(networkConnectionListener)
removeConnectionListener(connectionListener)
- removeVideoTrackRenders()
releaseCurrentSession()
releaseAudioManager()
@@ -113,17 +112,23 @@ class CallService : Service() {
notificationManager.cancelAll()
}
- override fun onBind(intent: Intent?): IBinder? {
+ override fun onBind(intent: Intent?): IBinder {
return callServiceBinder
}
private fun initNotification(): Notification {
+ var intentFlag = 0
+
val notifyIntent = Intent(this, CallActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ intentFlag = PendingIntent.FLAG_IMMUTABLE
+ }
+
val notifyPendingIntent = PendingIntent.getActivity(this, 0, notifyIntent,
- PendingIntent.FLAG_UPDATE_CURRENT)
+ intentFlag)
val notificationTitle = getString(R.string.notification_title)
var notificationText = getString(R.string.notification_text, "")
@@ -232,7 +237,7 @@ class CallService : Service() {
addSessionEventsListener(sessionEventsListener)
}
- fun initAudioManager() {
+ private fun initAudioManager() {
appRTCAudioManager = AppRTCAudioManager.create(this)
appRTCAudioManager.setOnWiredHeadsetStateListener { plugged, hasMicrophone ->
@@ -269,7 +274,6 @@ class CallService : Service() {
currentSession = null
}
- //Listeners
fun addConnectionListener(connectionListener: ConnectionListener?) {
QBChatService.getInstance().addConnectionListener(connectionListener)
}
@@ -294,11 +298,11 @@ class CallService : Service() {
currentSession?.removeVideoTrackCallbacksListener(callback)
}
- fun addSignalingListener(callback: QBRTCSignalingCallback?) {
+ private fun addSignalingListener(callback: QBRTCSignalingCallback?) {
currentSession?.addSignalingCallback(callback)
}
- fun removeSignalingListener(callback: QBRTCSignalingCallback?) {
+ private fun removeSignalingListener(callback: QBRTCSignalingCallback?) {
currentSession?.removeSignalingCallback(callback)
}
@@ -310,7 +314,6 @@ class CallService : Service() {
rtcClient.removeSessionsCallbacksListener(callback)
}
- //Common methods
fun acceptCall(userInfo: Map) {
currentSession?.acceptCall(userInfo)
}
@@ -428,28 +431,12 @@ class CallService : Service() {
}
private fun removeVideoTrack(userId: Int) {
+ val videoTrack = getVideoTrack(userId)
+ val renderer =videoTrack?.renderer
+ videoTrack?.removeRenderer(renderer)
videoTrackMap.remove(userId)
}
- private fun removeVideoTrackRenders() {
- Log.d(TAG, "removeVideoTrackRenders")
- if (videoTrackMap.isNotEmpty()) {
- val entryIterator = videoTrackMap.entries.iterator()
- while (entryIterator.hasNext()) {
- val entry = entryIterator.next()
- val userId = entry.key
- val videoTrack = entry.value
- val qbUser = QBChatService.getInstance().user
- val remoteVideoTrack = userId != qbUser.id
- if (remoteVideoTrack) {
- videoTrack.renderer?.let {
- videoTrack.removeRenderer(it)
- }
- }
- }
- }
- }
-
fun setCallTimerCallback(callback: CallTimerListener) {
callTimerListener = callback
}
@@ -535,21 +522,23 @@ class CallService : Service() {
}
override fun onSessionStartClose(session: QBRTCSession?) {
- if (session == WebRtcSessionManager.getCurrentSession()) {
- CallService.stop(applicationContext)
- }
+ // empty
}
override fun onReceiveHangUpFromUser(session: QBRTCSession?, userID: Int?, p2: MutableMap?) {
stopRingtone()
if (session == WebRtcSessionManager.getCurrentSession()) {
- if (userID == session?.callerID) {
+ val numberOpponents = session?.opponents?.size
+ if (numberOpponents == ONE_OPPONENT) {
currentSession?.let {
it.hangUp(HashMap())
CallService.stop(this@CallService)
}
+ }else{
+ userID?.let {
+ removeVideoTrack(it)
+ }
}
- Log.d(TAG, "initiator hung up the call")
} else {
CallService.stop(this@CallService)
}
@@ -615,9 +604,6 @@ 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")
- userID?.let {
- removeVideoTrack(it)
- }
}
override fun onStateChanged(session: QBRTCSession?, sessionState: BaseSession.QBRTCSessionState?) {
@@ -627,7 +613,7 @@ class CallService : Service() {
private inner class QBRTCSignalingListener : QBRTCSignalingCallback {
override fun onSuccessSendingPacket(p0: QBSignalingSpec.QBSignalCMD?, p1: Int?) {
-
+ // empty
}
override fun onErrorSendingPacket(p0: QBSignalingSpec.QBSignalCMD?, p1: Int?, p2: QBRTCSignalException?) {
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
index 701b3459d..6adffca8f 100644
--- 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
@@ -6,6 +6,7 @@ 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
@@ -53,10 +54,17 @@ object ChatPingAlarmManager {
* @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
- pendingIntent = PendingIntent.getBroadcast(context, 0, Intent(PING_ALARM_ACTION), 0)
+
+ 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)
}
diff --git a/sample-videochat-kotlin/app/src/main/res/values/strings.xml b/sample-videochat-kotlin/app/src/main/res/values/strings.xml
index 96ab7e661..bc9947e70 100644
--- a/sample-videochat-kotlin/app/src/main/res/values/strings.xml
+++ b/sample-videochat-kotlin/app/src/main/res/values/strings.xml
@@ -160,7 +160,7 @@
answer_time_interval
- 60
+ 30
disconnect_time_interval
10
Dialing_time_interval
@@ -215,5 +215,6 @@
You can select up to %d opponents
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/build.gradle b/sample-videochat-kotlin/build.gradle
index d2e7db27a..cbe1ad7e0 100644
--- a/sample-videochat-kotlin/build.gradle
+++ b/sample-videochat-kotlin/build.gradle
@@ -1,22 +1,19 @@
buildscript {
repositories {
google()
- jcenter()
+ mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.2.0'
- classpath 'com.google.gms:google-services:4.1.0'
+ classpath 'com.android.tools.build:gradle:4.2.2'
+ classpath 'com.google.gms:google-services:4.3.10'
}
}
allprojects {
repositories {
google()
- jcenter()
- maven {
- url "https://github.com/QuickBlox/quickblox-android-sdk-releases/raw/master/"
- }
+ mavenCentral()
}
}
@@ -26,32 +23,22 @@ ext {
lintAbortOnError = false
// QuickBlox SDK version
- qbSdkVersion = '3.9.2'
+ qbSdkVersion = '3.9.15'
//Firebase
- firebaseCoreVersion = '16.0.8'
-
- //Glide
- glideVersion = '3.6.1'
+ firebaseCoreVersion = '20.1.2'
//Material
- materialVersion = '1.0.0'
+ materialVersion = '1.5.0'
//RobotoTextView
robotoTextViewVersion = '4.0.0'
//Android X
- fragmentAndroidXVersion = '1.0.0'
- lifecycleViewmodelAndroidXVersion = '1.0.0'
- coreKtxVersion = '1.0.1'
-
- //Crashlytics
- crashlyticsVersion = '2.9.5'
-
- //Fabric
- fabricToolsVersion = '1.27.0'
+ fragmentAndroidXVersion = '1.4.1'
+ lifecycleViewmodelAndroidXVersion = '2.4.1'
+ coreKtxVersion = '1.7.0'
//Kotlin
- kotlinGradlePluginVersion = '1.2.71'
- kotlinReflectVersion = '1.2.71'
+ kotlinGradlePluginVersion = '1.5.31'
}
\ No newline at end of file
diff --git a/sample-videochat-kotlin/gradle/wrapper/gradle-wrapper.jar b/sample-videochat-kotlin/gradle/wrapper/gradle-wrapper.jar
index f6b961fd5..758de960e 100644
Binary files a/sample-videochat-kotlin/gradle/wrapper/gradle-wrapper.jar and b/sample-videochat-kotlin/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/sample-videochat-kotlin/gradle/wrapper/gradle-wrapper.properties b/sample-videochat-kotlin/gradle/wrapper/gradle-wrapper.properties
index 9a4163a4f..4d9ca1649 100644
--- a/sample-videochat-kotlin/gradle/wrapper/gradle-wrapper.properties
+++ b/sample-videochat-kotlin/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists