Skip to content

Commit b49c7fe

Browse files
authored
Merge pull request #86 from webex/Rohit_Release_3.12.0
3.12.0 Release
2 parents a59cdd8 + d9a8ad8 commit b49c7fe

30 files changed

Lines changed: 384 additions & 101 deletions

File tree

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,19 +79,19 @@ This demo support Android device with **Android 7.0** or later
7979
- For Full SDK
8080
```
8181
dependencies {
82-
implementation 'com.ciscowebex:webexsdk:3.11.3'
82+
implementation 'com.ciscowebex:webexsdk:3.12.0'
8383
}
8484
```
8585
- For Meeting SDK
8686
```
8787
dependencies {
88-
implementation 'com.ciscowebex:webexsdk-meeting:3.11.3'
88+
implementation 'com.ciscowebex:webexsdk-meeting:3.12.0'
8989
}
9090
```
9191
- For WebexCalling SDK
9292
```
9393
dependencies {
94-
implementation 'com.ciscowebex:webexsdk-wxc:3.11.3'
94+
implementation 'com.ciscowebex:webexsdk-wxc:3.12.0'
9595
}
9696
```
9797

app/build.gradle

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ android {
3232
applicationId "com.cisco.sdk_android"
3333
minSdkVersion Versions.minSdk
3434
targetSdkVersion Versions.targetSdk
35-
versionCode 3110300
36-
versionName "3.11.3"
35+
versionCode 3120000
36+
versionName "3.12.0"
3737

3838
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
3939

@@ -121,9 +121,9 @@ android {
121121

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

128128
implementation fileTree(dir: "libs", include: ["*.jar"])
129129
implementation Dependencies.kotlinStdLib

app/src/androidTest/java/com/ciscowebex/androidsdk/kitchensink/teams/membership/TeamFragmentTest.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,13 @@ class TeamFragmentTest : KitchenSinkTest() {
7474
onView(withId(R.id.teamsRecyclerView)).check(matches(hasDescendant(withText(testTeam))))
7575
}
7676

77-
@Test
78-
fun addPersonToTeam_teamFragment(){
79-
goToMessagingActivity()
80-
onView(withId(R.id.teamsRecyclerView)).perform(RecyclerViewActions.actionOnItemAtPosition<TeamsClientViewHolder>(0, clickChildViewWithId(R.id.iv_add_to_team)))
81-
WaitUtils.sleep(TIME_1_SEC)
82-
intended(hasComponent(MessagingSearchActivity::class.java.name))
83-
}
77+
// @Test
78+
// fun addPersonToTeam_teamFragment(){
79+
// goToMessagingActivity()
80+
// onView(withId(R.id.teamsRecyclerView)).perform(RecyclerViewActions.actionOnItemAtPosition<TeamsClientViewHolder>(0, clickChildViewWithId(R.id.iv_add_to_team)))
81+
// WaitUtils.sleep(TIME_1_SEC)
82+
// intended(hasComponent(MessagingSearchActivity::class.java.name))
83+
// }
8484

8585
@Test
8686
fun testBottomSheetOptions_teamsFragment(){
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.ciscowebex.androidsdk.kitchensink.annotation
2+
3+
import android.content.Context
4+
import android.widget.FrameLayout
5+
import com.ciscowebex.androidsdk.annotation.renderer.LiveAnnotationRenderer
6+
7+
class AnnotationRenderer(requireContext: Context) {
8+
private val renderer = LiveAnnotationRenderer(requireContext)
9+
10+
interface AnnotationRendererCallback: LiveAnnotationRenderer.LiveAnnotationRendererCallback{
11+
}
12+
13+
fun startRendering(): Boolean {
14+
return renderer.startRendering()
15+
}
16+
17+
fun stopRendering() {
18+
renderer.stopRendering()
19+
}
20+
21+
fun renderData(data: String) {
22+
renderer.renderData(data)
23+
}
24+
25+
fun getAnnotationLayer(): FrameLayout? {
26+
return renderer.getAnnotationLayer()
27+
}
28+
29+
fun setAnnotationRendererCallback(callback: AnnotationRendererCallback) {
30+
renderer.setAnnotationRendererCallback(callback)
31+
}
32+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<resources>
2+
<string name="app_name">Kitchen Sink</string>
3+
<string name="kitchen_sink">Kitchen Sink</string>
4+
</resources>

app/src/main/java/com/ciscowebex/androidsdk/kitchensink/WebexRepository.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,15 @@ class WebexRepository(val webex: Webex) : WebexUCLoginDelegate, WebexAuthDelegat
701701
}
702702
}
703703
}
704+
705+
override fun onMoveMeetingFailed(call: Call?) {
706+
val observers: MutableList<CallObserver>? = _callObservers[_callId]
707+
observers?.let { it ->
708+
it.forEach { observer ->
709+
observer.onMoveMeetingFailed(call)
710+
}
711+
}
712+
}
704713
}
705714

706715
private fun registerCallObserver(call: Call) {

app/src/main/java/com/ciscowebex/androidsdk/kitchensink/WebexViewModel.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import com.ciscowebex.androidsdk.kitchensink.firebase.RegisterTokenService
1212
import com.ciscowebex.androidsdk.kitchensink.person.PersonModel
1313
import com.ciscowebex.androidsdk.CompletionHandler
1414
import com.ciscowebex.androidsdk.WebexError
15-
import com.ciscowebex.androidsdk.annotation.renderer.LiveAnnotationRenderer
1615
import com.google.android.gms.tasks.OnCompleteListener
1716
import com.google.android.gms.tasks.Task
1817
import com.google.firebase.messaging.FirebaseMessaging
@@ -21,6 +20,7 @@ import com.ciscowebex.androidsdk.auth.PhoneServiceRegistrationFailureReason
2120
import com.ciscowebex.androidsdk.auth.TokenAuthenticator
2221
import com.ciscowebex.androidsdk.auth.UCLoginServerConnectionStatus
2322
import com.ciscowebex.androidsdk.internal.ResultImpl
23+
import com.ciscowebex.androidsdk.kitchensink.annotation.AnnotationRenderer
2424
import com.ciscowebex.androidsdk.kitchensink.calling.CallObserverInterface
2525
import com.ciscowebex.androidsdk.kitchensink.utils.CallObjectStorage
2626
import com.ciscowebex.androidsdk.kitchensink.utils.Constants
@@ -45,6 +45,7 @@ import com.ciscowebex.androidsdk.phone.MediaStream
4545
import com.ciscowebex.androidsdk.phone.MediaStreamQuality
4646
import com.ciscowebex.androidsdk.phone.BreakoutSession
4747
import com.ciscowebex.androidsdk.phone.Breakout
48+
import com.ciscowebex.androidsdk.phone.CompanionMode
4849
import com.ciscowebex.androidsdk.phone.DirectTransferResult
4950
import com.ciscowebex.androidsdk.phone.InviteParticipantError
5051
import com.ciscowebex.androidsdk.phone.SwitchToAudioVideoCallResult
@@ -671,8 +672,8 @@ class WebexViewModel(val webex: Webex, val repository: WebexRepository) : BaseVi
671672
})
672673
}
673674

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

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

695696
override fun onLiveAnnotationsStarted() {
696697
annotationRenderer = renderer.apply {
697-
setAnnotationRendererCallback(object : LiveAnnotationRenderer.LiveAnnotationRendererCallback {
698+
setAnnotationRendererCallback(object : AnnotationRenderer.AnnotationRendererCallback {
698699
override fun onAnnotationRenderingReady() {
699700
Log.d(tag, "onAnnotationRenderingReady")
700701
}

app/src/main/java/com/ciscowebex/androidsdk/kitchensink/calling/CallActivity.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,12 @@ class CallActivity : BaseActivity(), CallControlsFragment.OnCallActionListener,
4545

4646

4747
companion object {
48-
fun getOutgoingIntent(context: Context, callerName: String, callType: Boolean): Intent {
48+
fun getOutgoingIntent(context: Context, callerName: String, callType: Boolean, moveMeeting: Boolean): Intent {
4949
val intent = Intent(context, CallActivity::class.java)
5050
intent.putExtra(Constants.Intent.CALLING_ACTIVITY_ID, 0)
5151
intent.putExtra(Constants.Intent.OUTGOING_CALL_CALLER_ID, callerName)
5252
intent.putExtra(Constants.Intent.CALL_TYPE, callType)
53+
intent.putExtra(Constants.Intent.MOVE_MEETING, moveMeeting)
5354
return intent
5455
}
5556
fun getIncomingIntent(context: Context, callId: String? = null): Intent {
@@ -87,8 +88,10 @@ class CallActivity : BaseActivity(), CallControlsFragment.OnCallActionListener,
8788
if (callingActivity == 0) {
8889
val callerId = intent.getStringExtra(Constants.Intent.OUTGOING_CALL_CALLER_ID)
8990
val switchToUcmOrBroadworksCall = intent.getBooleanExtra(Constants.Intent.CALL_TYPE, false)
91+
val moveMeeting = intent.getBooleanExtra(Constants.Intent.MOVE_MEETING, false)
92+
val companionMode: CompanionMode = if (moveMeeting) CompanionMode.MoveMeeting else CompanionMode.None
9093
callerId?.let {
91-
fragment.dialOutgoingCall(callerId, isCucmOrWxcCall = switchToUcmOrBroadworksCall)
94+
fragment.dialOutgoingCall(callerId, isCucmOrWxcCall = switchToUcmOrBroadworksCall, moveMeeting = companionMode)
9295
}
9396
} else if (intent.action == Constants.Action.WEBEX_CALL_ACTION){
9497
intent?.getStringExtra(Constants.Intent.CALL_ID) ?.let { callId ->
@@ -469,6 +472,10 @@ class CallActivity : BaseActivity(), CallControlsFragment.OnCallActionListener,
469472
TODO("Not yet implemented")
470473
}
471474

475+
override fun onMoveMeetingFailed(call: Call?) {
476+
TODO("Not yet implemented")
477+
}
478+
472479
override fun finish() {
473480
if(calls.size > 0){
474481
//Resume a queued call

app/src/main/java/com/ciscowebex/androidsdk/kitchensink/calling/CallControlsFragment.kt

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ import androidx.lifecycle.lifecycleScope
4545
import com.bumptech.glide.Glide
4646
import com.ciscowebex.androidsdk.CompletionHandler
4747
import com.ciscowebex.androidsdk.WebexError
48-
import com.ciscowebex.androidsdk.annotation.renderer.LiveAnnotationRenderer
4948
import com.ciscowebex.androidsdk.kitchensink.BuildConfig
5049
import com.ciscowebex.androidsdk.kitchensink.R
5150
import com.ciscowebex.androidsdk.kitchensink.WebexRepository
5251
import com.ciscowebex.androidsdk.kitchensink.WebexViewModel
52+
import com.ciscowebex.androidsdk.kitchensink.annotation.AnnotationRenderer
5353
import com.ciscowebex.androidsdk.kitchensink.auth.LoginActivity
5454
import com.ciscowebex.androidsdk.kitchensink.calling.captions.ClosedCaptionsController
5555
import com.ciscowebex.androidsdk.kitchensink.calling.captions.ClosedCaptionsViewModel
@@ -90,13 +90,16 @@ import com.ciscowebex.androidsdk.phone.Phone
9090
import com.ciscowebex.androidsdk.phone.VirtualBackground
9191
import com.ciscowebex.androidsdk.phone.Breakout
9292
import com.ciscowebex.androidsdk.phone.BreakoutSession
93+
import com.ciscowebex.androidsdk.phone.CompanionMode
9394
import com.ciscowebex.androidsdk.phone.ReceivingNoiseInfo
9495
import com.ciscowebex.androidsdk.phone.ShareConfig
9596
import com.ciscowebex.androidsdk.phone.annotation.LiveAnnotationsPolicy
9697
import com.ciscowebex.androidsdk.phone.closedCaptions.CaptionItem
9798
import com.ciscowebex.androidsdk.phone.closedCaptions.ClosedCaptionsInfo
99+
import com.ciscowebex.androidsdk.kitchensink.utils.GlobalExceptionHandler
98100
import org.koin.android.ext.android.inject
99101
import com.ciscowebex.androidsdk.utils.internal.MimeUtils
102+
import com.google.android.material.snackbar.Snackbar
100103
import kotlinx.coroutines.CoroutineScope
101104
import java.io.File
102105
import 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
}

app/src/main/java/com/ciscowebex/androidsdk/kitchensink/calling/CallObserverInterface.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,5 @@ interface CallObserverInterface {
4747
// Closedcaption
4848
fun onClosedCaptionsArrived(closedCaptions: CaptionItem)
4949
fun onClosedCaptionsInfoChanged(closedCaptionsInfo: ClosedCaptionsInfo)
50+
fun onMoveMeetingFailed(call: Call?)
5051
}

0 commit comments

Comments
 (0)