@@ -12,6 +12,7 @@ import com.ciscowebex.androidsdk.kitchensink.firebase.RegisterTokenService
12
12
import com.ciscowebex.androidsdk.kitchensink.person.PersonModel
13
13
import com.ciscowebex.androidsdk.CompletionHandler
14
14
import com.ciscowebex.androidsdk.WebexError
15
+ import com.ciscowebex.androidsdk.annotation.renderer.LiveAnnotationRenderer
15
16
import com.google.android.gms.tasks.OnCompleteListener
16
17
import com.google.android.gms.tasks.Task
17
18
import com.google.firebase.messaging.FirebaseMessaging
@@ -34,6 +35,7 @@ import com.ciscowebex.androidsdk.phone.CallMembership
34
35
import com.ciscowebex.androidsdk.phone.Phone
35
36
import com.ciscowebex.androidsdk.phone.CallAssociationType
36
37
import com.ciscowebex.androidsdk.phone.AdvancedSetting
38
+ import com.ciscowebex.androidsdk.phone.MakeHostError
37
39
import com.ciscowebex.androidsdk.phone.AuxStream
38
40
import com.ciscowebex.androidsdk.phone.VirtualBackground
39
41
import com.ciscowebex.androidsdk.phone.CameraExposureISO
@@ -44,10 +46,14 @@ import com.ciscowebex.androidsdk.phone.MediaStreamQuality
44
46
import com.ciscowebex.androidsdk.phone.BreakoutSession
45
47
import com.ciscowebex.androidsdk.phone.Breakout
46
48
import com.ciscowebex.androidsdk.phone.DirectTransferResult
49
+ import com.ciscowebex.androidsdk.phone.InviteParticipantError
47
50
import com.ciscowebex.androidsdk.phone.SwitchToAudioVideoCallResult
48
51
import com.ciscowebex.androidsdk.phone.PhoneConnectionResult
49
52
import com.ciscowebex.androidsdk.phone.ReceivingNoiseInfo
50
53
import com.ciscowebex.androidsdk.phone.ReceivingNoiseRemovalEnableResult
54
+ import com.ciscowebex.androidsdk.phone.ReclaimHostError
55
+ import com.ciscowebex.androidsdk.phone.annotation.LiveAnnotationListener
56
+ import com.ciscowebex.androidsdk.phone.annotation.LiveAnnotationsPolicy
51
57
import com.ciscowebex.androidsdk.phone.closedCaptions.CaptionItem
52
58
import com.ciscowebex.androidsdk.phone.closedCaptions.ClosedCaptionsInfo
53
59
import com.google.firebase.installations.FirebaseInstallations
@@ -98,6 +104,14 @@ class WebexViewModel(val webex: Webex, val repository: WebexRepository) : BaseVi
98
104
private val _initialSpacesSyncCompletedLiveData = MutableLiveData <Boolean >()
99
105
val initialSpacesSyncCompletedLiveData: LiveData <Boolean > = _initialSpacesSyncCompletedLiveData
100
106
107
+ private val _annotationEvent = MutableLiveData <AnnotationEvent >()
108
+ val annotationEvent: LiveData <AnnotationEvent > get() = _annotationEvent
109
+ sealed class AnnotationEvent {
110
+ data class PERMISSION_ASK (val personId : String ) : AnnotationEvent()
111
+ data class PERMISSION_EXPIRED (val personId : String ) : AnnotationEvent()
112
+ }
113
+
114
+
101
115
var selfPersonId: String? = null
102
116
var compositedLayoutState = MediaOption .CompositedVideoLayout .NOT_SUPPORTED
103
117
@@ -403,6 +417,9 @@ class WebexViewModel(val webex: Webex, val repository: WebexRepository) : BaseVi
403
417
WebexError .ErrorCode .INVALID_PASSWORD_OR_HOST_KEY_WITH_CAPTCHA .code -> {
404
418
_callingLiveData .postValue(WebexRepository .CallLiveData (WebexRepository .CallEvent .InCorrectPasswordOrHostKeyWithCaptcha , null , error.data as Phone .Captcha ))
405
419
}
420
+ WebexError .ErrorCode .CANNOT_START_INSTANT_MEETING .code -> {
421
+ _callingLiveData .postValue(WebexRepository .CallLiveData (WebexRepository .CallEvent .CannotStartInstantMeeting , null , null , result.error?.errorMessage))
422
+ }
406
423
else -> {
407
424
_callingLiveData .postValue(WebexRepository .CallLiveData (WebexRepository .CallEvent .DialFailed , null , null , result.error?.errorMessage))
408
425
}
@@ -463,6 +480,7 @@ class WebexViewModel(val webex: Webex, val repository: WebexRepository) : BaseVi
463
480
override fun onDisconnected (event : CallObserver .CallDisconnectedEvent ? ) {
464
481
Log .d(tag, " CallObserver onDisconnected event: ${this @WebexViewModel} $callObserverInterface $event " )
465
482
callObserverInterface?.onDisconnected(call, event)
483
+ annotationRenderer?.stopRendering()
466
484
}
467
485
468
486
override fun onInfoChanged (call : Call ? ) {
@@ -621,15 +639,22 @@ class WebexViewModel(val webex: Webex, val repository: WebexRepository) : BaseVi
621
639
}
622
640
623
641
fun startShare (callId : String , shareConfig : ShareConfig ? ) {
624
- getCall(callId)?.startSharing(CompletionHandler { result ->
625
- _startShareLiveData .postValue(result.isSuccessful)
626
- }, shareConfig)
642
+ val call = getCall(callId)
643
+ call?.let {
644
+ it.startSharing(CompletionHandler { result ->
645
+ _startShareLiveData .postValue(result.isSuccessful)
646
+
647
+ }, shareConfig)
648
+ }
627
649
}
628
650
629
651
fun startShare (callId : String , notification : Notification ? , notificationId : Int , shareConfig : ShareConfig ? ) {
630
- getCall(callId)?.startSharing(notification, notificationId, CompletionHandler { result ->
631
- _startShareLiveData .postValue(result.isSuccessful)
632
- }, shareConfig)
652
+ val call = getCall(callId)
653
+ call?.let {
654
+ it.startSharing(notification, notificationId, CompletionHandler { result ->
655
+ _startShareLiveData .postValue(result.isSuccessful)
656
+ }, shareConfig)
657
+ }
633
658
}
634
659
635
660
fun setSendingSharing (callId : String , value : Boolean ) {
@@ -642,6 +667,80 @@ class WebexViewModel(val webex: Webex, val repository: WebexRepository) : BaseVi
642
667
})
643
668
}
644
669
670
+ private var annotationRenderer: LiveAnnotationRenderer ? = null
671
+ fun initalizeAnnotations (renderer : LiveAnnotationRenderer ) {
672
+ getCall(currentCallId.orEmpty())?.getLiveAnnotationHandle()?.let {annotations->
673
+
674
+ annotations.setLiveAnnotationsPolicy(LiveAnnotationsPolicy .NeedAskForAnnotate ){
675
+ if (it.isSuccessful) {
676
+ Log .d(tag, " setLiveAnnotationsPolicy successful" )
677
+ } else {
678
+ Log .d(tag, " setLiveAnnotationsPolicy error: ${it.error?.errorMessage} " )
679
+ }
680
+ }
681
+
682
+ annotations.setLiveAnnotationListener(object : LiveAnnotationListener {
683
+ override fun onLiveAnnotationRequestReceived (personId : String ) {
684
+ _annotationEvent .postValue(AnnotationEvent .PERMISSION_ASK (personId))
685
+ }
686
+
687
+ override fun onLiveAnnotationRequestExpired (personId : String ) {
688
+ _annotationEvent .postValue(AnnotationEvent .PERMISSION_EXPIRED (personId))
689
+ }
690
+
691
+ override fun onLiveAnnotationsStarted () {
692
+ annotationRenderer = renderer.apply {
693
+ setAnnotationRendererCallback(object : LiveAnnotationRenderer .LiveAnnotationRendererCallback {
694
+ override fun onAnnotationRenderingReady () {
695
+ Log .d(tag, " onAnnotationRenderingReady" )
696
+ }
697
+
698
+ override fun onAnnotationRenderingStopped () {
699
+ Log .d(tag, " onAnnotationRenderingStopped" )
700
+ getCall(currentCallId.orEmpty())?.getLiveAnnotationHandle()?.stopLiveAnnotations()
701
+ annotationRenderer = null
702
+ }
703
+ })
704
+ startRendering()
705
+ }
706
+ }
707
+
708
+ override fun onLiveAnnotationDataArrived (data : String ) {
709
+ annotationRenderer?.renderData(data)
710
+ }
711
+
712
+ override fun onLiveAnnotationsStopped () {
713
+ annotationRenderer?.stopRendering()
714
+ }
715
+
716
+ })
717
+ }
718
+ }
719
+
720
+ fun handleAnnotationPermission (grant : Boolean , personId : String ) {
721
+ getCall(currentCallId.orEmpty())?.getLiveAnnotationHandle()?.respondToLiveAnnotationRequest(personId, grant) {
722
+ if (it.isSuccessful) {
723
+ Log .d(tag, " permission handled" )
724
+ } else {
725
+ Log .d(tag, " permission error: ${it.error?.errorMessage} " )
726
+ }
727
+ }
728
+ }
729
+
730
+ fun getCurrentLiveAnnotationPolicy (): LiveAnnotationsPolicy ? {
731
+ return getCall(currentCallId.orEmpty())?.getLiveAnnotationHandle()?.getLiveAnnotationsPolicy()
732
+ }
733
+
734
+ fun setLiveAnnotationPolicy (policy : LiveAnnotationsPolicy ) {
735
+ getCall(currentCallId.orEmpty())?.getLiveAnnotationHandle()?.setLiveAnnotationsPolicy(policy) {
736
+ if (it.isSuccessful) {
737
+ Log .d(tag, " setLiveAnnotationsPolicy successful" )
738
+ } else {
739
+ Log .d(tag, " setLiveAnnotationsPolicy error: ${it.error?.errorMessage} " )
740
+ }
741
+ }
742
+ }
743
+
645
744
fun sendFeedback (callId : String , rating : Int , comment : String ) {
646
745
getCall(callId)?.sendFeedback(rating, comment)
647
746
}
@@ -1268,6 +1367,30 @@ class WebexViewModel(val webex: Webex, val repository: WebexRepository) : BaseVi
1268
1367
return webex.phone.getCallingType()
1269
1368
}
1270
1369
1370
+ fun makeHost (participantId : String , handler : CompletionHandler <MakeHostError >) {
1371
+ getCall(currentCallId.orEmpty())?.makeHost(participantId) { result ->
1372
+ if (result.isSuccessful) {
1373
+ Log .d(tag, " Make host successful" )
1374
+ handler.onComplete(ResultImpl .success())
1375
+ } else {
1376
+ Log .d(tag, " Make host failed" )
1377
+ handler.onComplete(ResultImpl .error(result.error?.errorMessage))
1378
+ }
1379
+ }
1380
+ }
1381
+
1382
+ fun reclaimHost (hostKey : String , handler : CompletionHandler <ReclaimHostError >) {
1383
+ getCall(currentCallId.orEmpty())?.reclaimHost(hostKey) { result ->
1384
+ if (result.isSuccessful) {
1385
+ Log .d(tag, " reclaimHost successful" )
1386
+ handler.onComplete(ResultImpl .success())
1387
+ } else {
1388
+ Log .d(tag, " reclaimHost failed" )
1389
+ handler.onComplete(ResultImpl .error(result.error?.errorMessage))
1390
+ }
1391
+ }
1392
+ }
1393
+
1271
1394
fun setOnInitialSpacesSyncCompletedListener () {
1272
1395
repository.setOnInitialSpacesSyncCompletedListener() {
1273
1396
_initialSpacesSyncCompletedLiveData .postValue(true )
@@ -1294,6 +1417,18 @@ class WebexViewModel(val webex: Webex, val repository: WebexRepository) : BaseVi
1294
1417
return getCall(currentCallId.orEmpty())?.isVideoEnabled() ? : false
1295
1418
}
1296
1419
1420
+ fun inviteParticipant (invitee : String , callback : CompletionHandler <InviteParticipantError >) {
1421
+ getCall(currentCallId.orEmpty())?.inviteParticipant(invitee) { result ->
1422
+ if (result.isSuccessful) {
1423
+ Log .d(tag, " InviteParticipant successful" )
1424
+ callback.onComplete(ResultImpl .success())
1425
+ } else {
1426
+ Log .d(tag, " InviteParticipant failed" )
1427
+ callback.onComplete(ResultImpl .error(result.error?.errorMessage))
1428
+ }
1429
+ }
1430
+ }
1431
+
1297
1432
fun cleanup () {
1298
1433
repository.removeIncomingCallListener(" viewmodel" + this )
1299
1434
for (entry in callObserverMap.entries.iterator()) {
@@ -1317,4 +1452,5 @@ class WebexViewModel(val webex: Webex, val repository: WebexRepository) : BaseVi
1317
1452
writer.println (" ******************" )
1318
1453
repository.printObservers(writer)
1319
1454
}
1455
+
1320
1456
}
0 commit comments