@@ -45,11 +45,11 @@ import androidx.lifecycle.lifecycleScope
4545import com.bumptech.glide.Glide
4646import com.ciscowebex.androidsdk.CompletionHandler
4747import com.ciscowebex.androidsdk.WebexError
48- import com.ciscowebex.androidsdk.annotation.renderer.LiveAnnotationRenderer
4948import com.ciscowebex.androidsdk.kitchensink.BuildConfig
5049import com.ciscowebex.androidsdk.kitchensink.R
5150import com.ciscowebex.androidsdk.kitchensink.WebexRepository
5251import com.ciscowebex.androidsdk.kitchensink.WebexViewModel
52+ import com.ciscowebex.androidsdk.kitchensink.annotation.AnnotationRenderer
5353import com.ciscowebex.androidsdk.kitchensink.auth.LoginActivity
5454import com.ciscowebex.androidsdk.kitchensink.calling.captions.ClosedCaptionsController
5555import com.ciscowebex.androidsdk.kitchensink.calling.captions.ClosedCaptionsViewModel
@@ -90,13 +90,16 @@ import com.ciscowebex.androidsdk.phone.Phone
9090import com.ciscowebex.androidsdk.phone.VirtualBackground
9191import com.ciscowebex.androidsdk.phone.Breakout
9292import com.ciscowebex.androidsdk.phone.BreakoutSession
93+ import com.ciscowebex.androidsdk.phone.CompanionMode
9394import com.ciscowebex.androidsdk.phone.ReceivingNoiseInfo
9495import com.ciscowebex.androidsdk.phone.ShareConfig
9596import com.ciscowebex.androidsdk.phone.annotation.LiveAnnotationsPolicy
9697import com.ciscowebex.androidsdk.phone.closedCaptions.CaptionItem
9798import com.ciscowebex.androidsdk.phone.closedCaptions.ClosedCaptionsInfo
99+ import com.ciscowebex.androidsdk.kitchensink.utils.GlobalExceptionHandler
98100import org.koin.android.ext.android.inject
99101import com.ciscowebex.androidsdk.utils.internal.MimeUtils
102+ import com.google.android.material.snackbar.Snackbar
100103import kotlinx.coroutines.CoroutineScope
101104import java.io.File
102105import java.util.Date
@@ -142,6 +145,7 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
142145 private var isInPipMode = false
143146 private var screenShareOptionsDialog: AlertDialog ? = null
144147 private lateinit var annotationPermissionDialog: AlertDialog
148+ private lateinit var moveMeeting: CompanionMode
145149
146150 // Is true when trying to join a Breakout Session, and becomes false when successfully joined or error occurs
147151 // Call onDisconnected is fired when user is the last one to leave main session and tries to join a breakout session.
@@ -237,7 +241,7 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
237241 binding.ibHoldCall.isSelected = isOnHold ? : false
238242 }
239243
240- private fun getMediaOption (isModerator : Boolean = false, pin : String = "", captcha : String = "", captchaId : String = ""): MediaOption {
244+ private fun getMediaOption (isModerator : Boolean = false, pin : String = "", captcha : String = "", captchaId : String = "", companionMode : CompanionMode = CompanionMode . None ): MediaOption {
241245 val mediaOption: MediaOption
242246 if (webexViewModel.callCapability == WebexRepository .CallCap .Audio_Only ) {
243247 mediaOption = MediaOption .audioOnly()
@@ -249,17 +253,18 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
249253 mediaOption.setPin(pin)
250254 mediaOption.setCaptchaCode(captcha)
251255 mediaOption.setCaptchaId(captchaId)
256+ mediaOption.setCompanionMode(companionMode)
252257 return mediaOption
253258 }
254259
255- fun dialOutgoingCall (callerId : String , isModerator : Boolean = false, pin : String = "", captcha : String = "", captchaId : String = "", isCucmOrWxcCall : Boolean ) {
260+ fun dialOutgoingCall (callerId : String , isModerator : Boolean = false, pin : String = "", captcha : String = "", captchaId : String = "", isCucmOrWxcCall : Boolean , moveMeeting : CompanionMode = CompanionMode . None ) {
256261 Log .d(TAG , " dialOutgoingCall" )
257262 this .callerId = callerId
258263 if (isCucmOrWxcCall) {
259- webexViewModel.dialPhoneNumber(callerId, getMediaOption(isModerator, pin, captcha, captchaId))
264+ webexViewModel.dialPhoneNumber(callerId, getMediaOption(isModerator, pin, captcha, captchaId, moveMeeting ))
260265 }
261266 else {
262- webexViewModel.dial(callerId, getMediaOption(isModerator, pin, captcha, captchaId))
267+ webexViewModel.dial(callerId, getMediaOption(isModerator, pin, captcha, captchaId, moveMeeting ))
263268 }
264269 }
265270
@@ -280,7 +285,9 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
280285 " isSelfCreator: ${webexViewModel.isSelfCreator()} , " +
281286 " isSpaceMeeting: ${webexViewModel.isSpaceMeeting()} , " +
282287 " isScheduledMeeting: ${webexViewModel.isScheduledMeeting()} " )
283-
288+ // Setting exception handler before making any call. Ideally this would be set in onCallConnected event
289+ // but due to codegen limitation, we are setting it here.
290+ Thread .setDefaultUncaughtExceptionHandler(GlobalExceptionHandler ())
284291 onCallConnected(call?.getCallId().orEmpty(), call?.isCUCMCall() ? : false , call?.isWebexCallingOrWebexForBroadworks() ? : false )
285292 webexViewModel.sendFeedback(call?.getCallId().orEmpty(), 5 , " Testing Comments SDK-v3" )
286293 webexViewModel.setShareMaxCaptureFPSSetting(30 )
@@ -318,7 +325,7 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
318325
319326 override fun onDisconnected (call : Call ? , event : CallObserver .CallDisconnectedEvent ? ) {
320327 Log .d(TAG , " CallObserver onDisconnected : " + call?.getCallId())
321-
328+ Thread .setDefaultUncaughtExceptionHandler( null )
322329 var callFailed = false
323330 var callEnded = false
324331 var localClose = false
@@ -349,6 +356,7 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
349356 }
350357 is CallObserver .OtherConnected -> {
351358 Log .d(TAG , " CallObserver OtherConnected" )
359+ callEnded = true
352360 }
353361 is CallObserver .OtherDeclined -> {
354362 Log .d(TAG , " CallObserver OtherDeclined" )
@@ -808,7 +816,7 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
808816
809817 override fun onClosedCaptionsArrived (captions : CaptionItem ) {
810818 CoroutineScope (Dispatchers .Main ).launch {
811- captionsController.showCaptionView(binding.rootLayout , captions)
819+ captionsController.showCaptionView(binding.root , captions)
812820 if (captions.isFinal) {
813821 captionsViewModel.updateData(captions)
814822 Log .d(TAG , " Captions are arrived from ${captions.getDisplayName()} " )
@@ -828,6 +836,10 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
828836 }
829837 }
830838
839+ override fun onMoveMeetingFailed (call : Call ? ) {
840+ showDialogWithMessage(requireContext(), R .string.move_meeting_failed, getString(R .string.move_meeting_failed_message))
841+ }
842+
831843 @SuppressLint(" NotifyDataSetChanged" )
832844 private fun observerCallLiveData () {
833845
@@ -842,7 +854,7 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
842854 if (it) {
843855 Log .d(TAG , " startShareLiveData success" )
844856 // For this share screen session initialize live annotations
845- webexViewModel.initalizeAnnotations(LiveAnnotationRenderer (requireContext()))
857+ webexViewModel.initalizeAnnotations(AnnotationRenderer (requireContext()))
846858 if (BuildConfig .FLAVOR != " wxc" ) {
847859 binding.annotationPolicy.visibility = VISIBLE
848860 binding.annotationPolicy.text = webexViewModel.getCurrentLiveAnnotationPolicy().toString()
@@ -1208,7 +1220,7 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
12081220 dialOutgoingCall(callerId, isHost,
12091221 pinTitleEditText.text.toString(),
12101222 captchaInputText.text.toString(),
1211- data?.getId()? : " " , false )
1223+ data?.getId()? : " " , false , moveMeeting )
12121224 }
12131225 }
12141226 }
@@ -1479,6 +1491,11 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
14791491 {toggleAudioMode(AudioMode .SPEAKER )}, {toggleAudioMode(AudioMode .BLUETOOTH )}, {toggleAudioMode(AudioMode .WIRED_HEADSET )})
14801492
14811493 callingActivity = bundle?.getInt(Constants .Intent .CALLING_ACTIVITY_ID , 0 )!!
1494+ moveMeeting = if (bundle.getBoolean(Constants .Intent .MOVE_MEETING , false )) {
1495+ CompanionMode .MoveMeeting
1496+ } else {
1497+ CompanionMode .None
1498+ }
14821499 val incomingCallId = bundle.getString(Constants .Intent .CALL_ID ) ? : " "
14831500 if (callingActivity == 1 ) {
14841501 isIncomingActivity = true
@@ -2872,10 +2889,10 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
28722889 showDialogForHostKey(requireContext(), getString(R .string.enter_host_key), onPositiveButtonClick = { dialog: DialogInterface , number: String ->
28732890 webexViewModel.reclaimHost(number){
28742891 if (it.isSuccessful) {
2875- showToast (" Reclaim Host Successful" )
2892+ showSnackbar (" Reclaim Host Successful" )
28762893 Log .d(TAG , " Reclaim Host Successful" )
28772894 } else {
2878- showToast (" Reclaim Host failed ${it.error?.errorMessage} " )
2895+ showSnackbar (" Reclaim Host failed ${it.error?.errorMessage} " )
28792896 Log .d(TAG , " Reclaim Host failed ${it.error?.errorMessage} " )
28802897 }
28812898 }
@@ -3242,7 +3259,8 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
32423259 mediaPlayer.reset()
32433260 super .onStop()
32443261 }
3245- private fun showToast (message : String ) {
3246- Toast .makeText(requireContext(), message, Toast .LENGTH_LONG ).show()
3262+
3263+ private fun showSnackbar (message : String ) {
3264+ Snackbar .make(binding.root, message, Snackbar .LENGTH_LONG ).show()
32473265 }
32483266}
0 commit comments