Skip to content

Commit

Permalink
Merge pull request #87 from webex/Release/3.12.0
Browse files Browse the repository at this point in the history
Release 3.12.0
  • Loading branch information
ciscoRankush authored Jul 8, 2024
2 parents a59cdd8 + b49c7fe commit 7baf279
Show file tree
Hide file tree
Showing 30 changed files with 384 additions and 101 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,19 +79,19 @@ This demo support Android device with **Android 7.0** or later
- For Full SDK
```
dependencies {
implementation 'com.ciscowebex:webexsdk:3.11.3'
implementation 'com.ciscowebex:webexsdk:3.12.0'
}
```
- For Meeting SDK
```
dependencies {
implementation 'com.ciscowebex:webexsdk-meeting:3.11.3'
implementation 'com.ciscowebex:webexsdk-meeting:3.12.0'
}
```
- For WebexCalling SDK
```
dependencies {
implementation 'com.ciscowebex:webexsdk-wxc:3.11.3'
implementation 'com.ciscowebex:webexsdk-wxc:3.12.0'
}
```
Expand Down
10 changes: 5 additions & 5 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ android {
applicationId "com.cisco.sdk_android"
minSdkVersion Versions.minSdk
targetSdkVersion Versions.targetSdk
versionCode 3110300
versionName "3.11.3"
versionCode 3120000
versionName "3.12.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

Expand Down Expand Up @@ -121,9 +121,9 @@ android {

dependencies {
//At a time only one WebexSDK should be used.
implementation 'com.ciscowebex:webexsdk:3.11.3' // For full flavor
//implementation 'com.ciscowebex:webexsdk-wxc:3.11.3' //For webexCalling flavor
//implementation 'com.ciscowebex:webexsdk-meeting:3.11.3' // For meeting flavor
implementation 'com.ciscowebex:webexsdk:3.12.0' // For full flavor
//implementation 'com.ciscowebex:webexsdk-wxc:3.12.0' //For webexCalling flavor
//implementation 'com.ciscowebex:webexsdk-meeting:3.12.0' // For meeting flavor

implementation fileTree(dir: "libs", include: ["*.jar"])
implementation Dependencies.kotlinStdLib
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,13 @@ class TeamFragmentTest : KitchenSinkTest() {
onView(withId(R.id.teamsRecyclerView)).check(matches(hasDescendant(withText(testTeam))))
}

@Test
fun addPersonToTeam_teamFragment(){
goToMessagingActivity()
onView(withId(R.id.teamsRecyclerView)).perform(RecyclerViewActions.actionOnItemAtPosition<TeamsClientViewHolder>(0, clickChildViewWithId(R.id.iv_add_to_team)))
WaitUtils.sleep(TIME_1_SEC)
intended(hasComponent(MessagingSearchActivity::class.java.name))
}
// @Test
// fun addPersonToTeam_teamFragment(){
// goToMessagingActivity()
// onView(withId(R.id.teamsRecyclerView)).perform(RecyclerViewActions.actionOnItemAtPosition<TeamsClientViewHolder>(0, clickChildViewWithId(R.id.iv_add_to_team)))
// WaitUtils.sleep(TIME_1_SEC)
// intended(hasComponent(MessagingSearchActivity::class.java.name))
// }

@Test
fun testBottomSheetOptions_teamsFragment(){
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.ciscowebex.androidsdk.kitchensink.annotation

import android.content.Context
import android.widget.FrameLayout
import com.ciscowebex.androidsdk.annotation.renderer.LiveAnnotationRenderer

class AnnotationRenderer(requireContext: Context) {
private val renderer = LiveAnnotationRenderer(requireContext)

interface AnnotationRendererCallback: LiveAnnotationRenderer.LiveAnnotationRendererCallback{
}

fun startRendering(): Boolean {
return renderer.startRendering()
}

fun stopRendering() {
renderer.stopRendering()
}

fun renderData(data: String) {
renderer.renderData(data)
}

fun getAnnotationLayer(): FrameLayout? {
return renderer.getAnnotationLayer()
}

fun setAnnotationRendererCallback(callback: AnnotationRendererCallback) {
renderer.setAnnotationRendererCallback(callback)
}
}
4 changes: 4 additions & 0 deletions app/src/full/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<resources>
<string name="app_name">Kitchen Sink</string>
<string name="kitchen_sink">Kitchen Sink</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,15 @@ class WebexRepository(val webex: Webex) : WebexUCLoginDelegate, WebexAuthDelegat
}
}
}

override fun onMoveMeetingFailed(call: Call?) {
val observers: MutableList<CallObserver>? = _callObservers[_callId]
observers?.let { it ->
it.forEach { observer ->
observer.onMoveMeetingFailed(call)
}
}
}
}

private fun registerCallObserver(call: Call) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import com.ciscowebex.androidsdk.kitchensink.firebase.RegisterTokenService
import com.ciscowebex.androidsdk.kitchensink.person.PersonModel
import com.ciscowebex.androidsdk.CompletionHandler
import com.ciscowebex.androidsdk.WebexError
import com.ciscowebex.androidsdk.annotation.renderer.LiveAnnotationRenderer
import com.google.android.gms.tasks.OnCompleteListener
import com.google.android.gms.tasks.Task
import com.google.firebase.messaging.FirebaseMessaging
Expand All @@ -21,6 +20,7 @@ import com.ciscowebex.androidsdk.auth.PhoneServiceRegistrationFailureReason
import com.ciscowebex.androidsdk.auth.TokenAuthenticator
import com.ciscowebex.androidsdk.auth.UCLoginServerConnectionStatus
import com.ciscowebex.androidsdk.internal.ResultImpl
import com.ciscowebex.androidsdk.kitchensink.annotation.AnnotationRenderer
import com.ciscowebex.androidsdk.kitchensink.calling.CallObserverInterface
import com.ciscowebex.androidsdk.kitchensink.utils.CallObjectStorage
import com.ciscowebex.androidsdk.kitchensink.utils.Constants
Expand All @@ -45,6 +45,7 @@ import com.ciscowebex.androidsdk.phone.MediaStream
import com.ciscowebex.androidsdk.phone.MediaStreamQuality
import com.ciscowebex.androidsdk.phone.BreakoutSession
import com.ciscowebex.androidsdk.phone.Breakout
import com.ciscowebex.androidsdk.phone.CompanionMode
import com.ciscowebex.androidsdk.phone.DirectTransferResult
import com.ciscowebex.androidsdk.phone.InviteParticipantError
import com.ciscowebex.androidsdk.phone.SwitchToAudioVideoCallResult
Expand Down Expand Up @@ -671,8 +672,8 @@ class WebexViewModel(val webex: Webex, val repository: WebexRepository) : BaseVi
})
}

private var annotationRenderer: LiveAnnotationRenderer? = null
fun initalizeAnnotations(renderer: LiveAnnotationRenderer) {
private var annotationRenderer: AnnotationRenderer? = null
fun initalizeAnnotations(renderer: AnnotationRenderer) {
getCall(currentCallId.orEmpty())?.getLiveAnnotationHandle()?.let {annotations->

annotations.setLiveAnnotationsPolicy(LiveAnnotationsPolicy.NeedAskForAnnotate){
Expand All @@ -694,7 +695,7 @@ class WebexViewModel(val webex: Webex, val repository: WebexRepository) : BaseVi

override fun onLiveAnnotationsStarted() {
annotationRenderer = renderer.apply {
setAnnotationRendererCallback(object : LiveAnnotationRenderer.LiveAnnotationRendererCallback {
setAnnotationRendererCallback(object : AnnotationRenderer.AnnotationRendererCallback {
override fun onAnnotationRenderingReady() {
Log.d(tag, "onAnnotationRenderingReady")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,12 @@ class CallActivity : BaseActivity(), CallControlsFragment.OnCallActionListener,


companion object {
fun getOutgoingIntent(context: Context, callerName: String, callType: Boolean): Intent {
fun getOutgoingIntent(context: Context, callerName: String, callType: Boolean, moveMeeting: Boolean): Intent {
val intent = Intent(context, CallActivity::class.java)
intent.putExtra(Constants.Intent.CALLING_ACTIVITY_ID, 0)
intent.putExtra(Constants.Intent.OUTGOING_CALL_CALLER_ID, callerName)
intent.putExtra(Constants.Intent.CALL_TYPE, callType)
intent.putExtra(Constants.Intent.MOVE_MEETING, moveMeeting)
return intent
}
fun getIncomingIntent(context: Context, callId: String? = null): Intent {
Expand Down Expand Up @@ -87,8 +88,10 @@ class CallActivity : BaseActivity(), CallControlsFragment.OnCallActionListener,
if (callingActivity == 0) {
val callerId = intent.getStringExtra(Constants.Intent.OUTGOING_CALL_CALLER_ID)
val switchToUcmOrBroadworksCall = intent.getBooleanExtra(Constants.Intent.CALL_TYPE, false)
val moveMeeting = intent.getBooleanExtra(Constants.Intent.MOVE_MEETING, false)
val companionMode: CompanionMode = if (moveMeeting) CompanionMode.MoveMeeting else CompanionMode.None
callerId?.let {
fragment.dialOutgoingCall(callerId, isCucmOrWxcCall = switchToUcmOrBroadworksCall)
fragment.dialOutgoingCall(callerId, isCucmOrWxcCall = switchToUcmOrBroadworksCall, moveMeeting = companionMode)
}
} else if (intent.action == Constants.Action.WEBEX_CALL_ACTION){
intent?.getStringExtra(Constants.Intent.CALL_ID) ?.let { callId ->
Expand Down Expand Up @@ -469,6 +472,10 @@ class CallActivity : BaseActivity(), CallControlsFragment.OnCallActionListener,
TODO("Not yet implemented")
}

override fun onMoveMeetingFailed(call: Call?) {
TODO("Not yet implemented")
}

override fun finish() {
if(calls.size > 0){
//Resume a queued call
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.Glide
import com.ciscowebex.androidsdk.CompletionHandler
import com.ciscowebex.androidsdk.WebexError
import com.ciscowebex.androidsdk.annotation.renderer.LiveAnnotationRenderer
import com.ciscowebex.androidsdk.kitchensink.BuildConfig
import com.ciscowebex.androidsdk.kitchensink.R
import com.ciscowebex.androidsdk.kitchensink.WebexRepository
import com.ciscowebex.androidsdk.kitchensink.WebexViewModel
import com.ciscowebex.androidsdk.kitchensink.annotation.AnnotationRenderer
import com.ciscowebex.androidsdk.kitchensink.auth.LoginActivity
import com.ciscowebex.androidsdk.kitchensink.calling.captions.ClosedCaptionsController
import com.ciscowebex.androidsdk.kitchensink.calling.captions.ClosedCaptionsViewModel
Expand Down Expand Up @@ -90,13 +90,16 @@ import com.ciscowebex.androidsdk.phone.Phone
import com.ciscowebex.androidsdk.phone.VirtualBackground
import com.ciscowebex.androidsdk.phone.Breakout
import com.ciscowebex.androidsdk.phone.BreakoutSession
import com.ciscowebex.androidsdk.phone.CompanionMode
import com.ciscowebex.androidsdk.phone.ReceivingNoiseInfo
import com.ciscowebex.androidsdk.phone.ShareConfig
import com.ciscowebex.androidsdk.phone.annotation.LiveAnnotationsPolicy
import com.ciscowebex.androidsdk.phone.closedCaptions.CaptionItem
import com.ciscowebex.androidsdk.phone.closedCaptions.ClosedCaptionsInfo
import com.ciscowebex.androidsdk.kitchensink.utils.GlobalExceptionHandler
import org.koin.android.ext.android.inject
import com.ciscowebex.androidsdk.utils.internal.MimeUtils
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.CoroutineScope
import java.io.File
import java.util.Date
Expand Down Expand Up @@ -142,6 +145,7 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
private var isInPipMode = false
private var screenShareOptionsDialog: AlertDialog? = null
private lateinit var annotationPermissionDialog: AlertDialog
private lateinit var moveMeeting: CompanionMode

// Is true when trying to join a Breakout Session, and becomes false when successfully joined or error occurs
// Call onDisconnected is fired when user is the last one to leave main session and tries to join a breakout session.
Expand Down Expand Up @@ -237,7 +241,7 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
binding.ibHoldCall.isSelected = isOnHold ?: false
}

private fun getMediaOption(isModerator: Boolean = false, pin: String = "", captcha: String = "", captchaId: String = ""): MediaOption {
private fun getMediaOption(isModerator: Boolean = false, pin: String = "", captcha: String = "", captchaId: String = "", companionMode: CompanionMode = CompanionMode.None): MediaOption {
val mediaOption: MediaOption
if (webexViewModel.callCapability == WebexRepository.CallCap.Audio_Only) {
mediaOption = MediaOption.audioOnly()
Expand All @@ -249,17 +253,18 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
mediaOption.setPin(pin)
mediaOption.setCaptchaCode(captcha)
mediaOption.setCaptchaId(captchaId)
mediaOption.setCompanionMode(companionMode)
return mediaOption
}

fun dialOutgoingCall(callerId: String, isModerator: Boolean = false, pin: String = "", captcha: String = "", captchaId: String = "", isCucmOrWxcCall: Boolean) {
fun dialOutgoingCall(callerId: String, isModerator: Boolean = false, pin: String = "", captcha: String = "", captchaId: String = "", isCucmOrWxcCall: Boolean, moveMeeting: CompanionMode = CompanionMode.None) {
Log.d(TAG, "dialOutgoingCall")
this.callerId = callerId
if(isCucmOrWxcCall) {
webexViewModel.dialPhoneNumber(callerId, getMediaOption(isModerator, pin, captcha, captchaId))
webexViewModel.dialPhoneNumber(callerId, getMediaOption(isModerator, pin, captcha, captchaId, moveMeeting))
}
else {
webexViewModel.dial(callerId, getMediaOption(isModerator, pin, captcha, captchaId))
webexViewModel.dial(callerId, getMediaOption(isModerator, pin, captcha, captchaId, moveMeeting))
}
}

Expand All @@ -280,7 +285,9 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
"isSelfCreator: ${webexViewModel.isSelfCreator()}, " +
"isSpaceMeeting: ${webexViewModel.isSpaceMeeting()}, "+
"isScheduledMeeting: ${webexViewModel.isScheduledMeeting()}")

// Setting exception handler before making any call. Ideally this would be set in onCallConnected event
// but due to codegen limitation, we are setting it here.
Thread.setDefaultUncaughtExceptionHandler(GlobalExceptionHandler())
onCallConnected(call?.getCallId().orEmpty(), call?.isCUCMCall() ?: false, call?.isWebexCallingOrWebexForBroadworks() ?: false)
webexViewModel.sendFeedback(call?.getCallId().orEmpty(), 5, "Testing Comments SDK-v3")
webexViewModel.setShareMaxCaptureFPSSetting(30)
Expand Down Expand Up @@ -318,7 +325,7 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface

override fun onDisconnected(call: Call?, event: CallObserver.CallDisconnectedEvent?) {
Log.d(TAG, "CallObserver onDisconnected : " + call?.getCallId())

Thread.setDefaultUncaughtExceptionHandler(null)
var callFailed = false
var callEnded = false
var localClose = false
Expand Down Expand Up @@ -349,6 +356,7 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
}
is CallObserver.OtherConnected -> {
Log.d(TAG, "CallObserver OtherConnected")
callEnded = true
}
is CallObserver.OtherDeclined -> {
Log.d(TAG, "CallObserver OtherDeclined")
Expand Down Expand Up @@ -808,7 +816,7 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface

override fun onClosedCaptionsArrived(captions: CaptionItem) {
CoroutineScope(Dispatchers.Main).launch {
captionsController.showCaptionView(binding.rootLayout, captions)
captionsController.showCaptionView(binding.root, captions)
if(captions.isFinal) {
captionsViewModel.updateData(captions)
Log.d(TAG, " Captions are arrived from ${captions.getDisplayName()}")
Expand All @@ -828,6 +836,10 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
}
}

override fun onMoveMeetingFailed(call: Call?) {
showDialogWithMessage(requireContext(), R.string.move_meeting_failed, getString(R.string.move_meeting_failed_message))
}

@SuppressLint("NotifyDataSetChanged")
private fun observerCallLiveData() {

Expand All @@ -842,7 +854,7 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
if (it) {
Log.d(TAG, "startShareLiveData success")
// For this share screen session initialize live annotations
webexViewModel.initalizeAnnotations(LiveAnnotationRenderer(requireContext()))
webexViewModel.initalizeAnnotations(AnnotationRenderer(requireContext()))
if(BuildConfig.FLAVOR != "wxc") {
binding.annotationPolicy.visibility = VISIBLE
binding.annotationPolicy.text = webexViewModel.getCurrentLiveAnnotationPolicy().toString()
Expand Down Expand Up @@ -1208,7 +1220,7 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
dialOutgoingCall(callerId, isHost,
pinTitleEditText.text.toString(),
captchaInputText.text.toString(),
data?.getId()?:"", false)
data?.getId()?:"", false, moveMeeting)
}
}
}
Expand Down Expand Up @@ -1479,6 +1491,11 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
{toggleAudioMode(AudioMode.SPEAKER)}, {toggleAudioMode(AudioMode.BLUETOOTH)}, {toggleAudioMode(AudioMode.WIRED_HEADSET)})

callingActivity = bundle?.getInt(Constants.Intent.CALLING_ACTIVITY_ID, 0)!!
moveMeeting = if(bundle.getBoolean(Constants.Intent.MOVE_MEETING, false)) {
CompanionMode.MoveMeeting
} else {
CompanionMode.None
}
val incomingCallId = bundle.getString(Constants.Intent.CALL_ID) ?: ""
if (callingActivity == 1) {
isIncomingActivity = true
Expand Down Expand Up @@ -2872,10 +2889,10 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
showDialogForHostKey(requireContext(), getString(R.string.enter_host_key), onPositiveButtonClick = { dialog: DialogInterface, number: String ->
webexViewModel.reclaimHost(number){
if (it.isSuccessful) {
showToast("Reclaim Host Successful")
showSnackbar("Reclaim Host Successful")
Log.d(TAG, "Reclaim Host Successful")
} else {
showToast("Reclaim Host failed ${it.error?.errorMessage}")
showSnackbar("Reclaim Host failed ${it.error?.errorMessage}")
Log.d(TAG, "Reclaim Host failed ${it.error?.errorMessage}")
}
}
Expand Down Expand Up @@ -3242,7 +3259,8 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
mediaPlayer.reset()
super.onStop()
}
private fun showToast(message: String) {
Toast.makeText(requireContext(), message, Toast.LENGTH_LONG).show()

private fun showSnackbar(message: String) {
Snackbar.make(binding.root, message, Snackbar.LENGTH_LONG).show()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,5 @@ interface CallObserverInterface {
// Closedcaption
fun onClosedCaptionsArrived(closedCaptions: CaptionItem)
fun onClosedCaptionsInfoChanged(closedCaptionsInfo: ClosedCaptionsInfo)
fun onMoveMeetingFailed(call: Call?)
}
Loading

0 comments on commit 7baf279

Please sign in to comment.