Skip to content

Commit eb691a4

Browse files
authored
Merge pull request #39 from webex/3.4.0-GA
3.4.0 release
2 parents b643bfa + 3a52d21 commit eb691a4

23 files changed

+229
-77
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ This demo support Android device with **Android 7.0** or later
6868
6969
```
7070
dependencies {
71-
implementation 'com.ciscowebex:androidsdk:3.2.1@aar'
71+
implementation 'com.ciscowebex:androidsdk:3.4.0@aar'
7272
}
7373
```
7474
@@ -84,4 +84,4 @@ For example see [README](https://github.com/webex/webex-android-sdk/blob/master/
8484
CLIENT_SECRET=""
8585
SCOPE=""
8686
REDIRECT_URI=""
87-
```
87+
```

app/build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ android {
1919
applicationId "com.cisco.sdk_android"
2020
minSdkVersion Versions.minSdk
2121
targetSdkVersion Versions.targetSdk
22-
versionCode 33000
23-
versionName "3.3.0"
22+
versionCode 34000
23+
versionName "3.4.0"
2424

2525
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
2626
buildConfigField "String", "CLIENT_ID", "${CLIENT_ID}"
@@ -62,7 +62,7 @@ android {
6262
}
6363

6464
dependencies {
65-
implementation 'com.ciscowebex:androidsdk:3.3.0@aar'
65+
implementation 'com.ciscowebex:androidsdk:3.4.0@aar'
6666

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

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,10 @@ class WebexViewModel(val webex: Webex, val repository: WebexRepository) : BaseVi
386386
override fun onPhotoCaptured(imageData: ByteArray?) {
387387
callObserverInterface?.onPhotoCaptured(imageData)
388388
}
389+
390+
override fun onMediaQualityInfoChanged(mediaQualityInfo: Call.MediaQualityInfo) {
391+
callObserverInterface?.onMediaQualityInfoChanged(mediaQualityInfo)
392+
}
389393
})
390394
}
391395

@@ -718,10 +722,14 @@ class WebexViewModel(val webex: Webex, val repository: WebexRepository) : BaseVi
718722
return getCall(callId)?.getVideoRenderViews() ?: Pair(null, null)
719723
}
720724

721-
fun setVideoRenderViews(callId: String, localVideoView: View, remoteVideoView: View) {
725+
fun setVideoRenderViews(callId: String, localVideoView: View?, remoteVideoView: View?) {
722726
getCall(callId)?.setVideoRenderViews(Pair(localVideoView, remoteVideoView))
723727
}
724728

729+
fun setVideoRenderViews(callId: String) {
730+
getCall(callId)?.setVideoRenderViews(null)
731+
}
732+
725733
fun forceSendingVideoLandscape(callId: String, forceLandscape: Boolean) {
726734
getCall(callId)?.forceSendingVideoLandscape(forceLandscape, CompletionHandler { result ->
727735
if (result.isSuccessful) {

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

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,15 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
9090
private var callerId: String = ""
9191
var bottomSheetFragment: BackgroundOptionsBottomSheetFragment? = null
9292

93+
enum class NetworkStatus {
94+
PoorUplink,
95+
PoorDownlink,
96+
Good,
97+
NoNetwork
98+
}
99+
100+
var currentNetworkStatus = NetworkStatus.Good
101+
93102
enum class ShareButtonState {
94103
OFF,
95104
ON,
@@ -268,7 +277,14 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
268277
*/
269278
onCallTerminated(call?.getCallId().orEmpty())
270279
} else {
271-
onCallDisconnected(call)
280+
/*
281+
* Below line takes care of ending the call if it is scheduled call and local leaves or ends the meeting
282+
* This fixes white screen issue when call is started from calendar meeting fragment
283+
*/
284+
if (!isIncomingActivity) {
285+
onCallTerminated(call?.getCallId().orEmpty())
286+
} else
287+
onCallDisconnected(call)
272288
}
273289
}
274290
}
@@ -420,6 +436,11 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
420436
}
421437
}
422438

439+
override fun onMediaQualityInfoChanged(mediaQualityInfo: Call.MediaQualityInfo) {
440+
Log.d(TAG, "CallObserver mediaQualityInfo changed : ${mediaQualityInfo.name}")
441+
updateNetworkStatusChange(mediaQualityInfo)
442+
}
443+
423444
@SuppressLint("NotifyDataSetChanged")
424445
private fun observerCallLiveData() {
425446

@@ -882,7 +903,8 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
882903
binding.ibMoreOption.setOnClickListener(this)
883904

884905
initAddedCallControls()
885-
906+
binding.ivNetworkSignal.setOnClickListener(this)
907+
binding.ivNetworkSignal.visibility = View.GONE
886908
}
887909

888910
override fun onClick(v: View?) {
@@ -944,6 +966,10 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
944966
showBottomSheet(webexViewModel.getCall(it))
945967
}
946968
}
969+
binding.ivNetworkSignal -> {
970+
val text = "Network Status : ${currentNetworkStatus.name}"
971+
Toast.makeText(requireContext(), text, Toast.LENGTH_SHORT).show()
972+
}
947973
else -> {
948974
}
949975
}
@@ -1213,6 +1239,7 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
12131239

12141240
val layout = webexViewModel.getCompositedLayout()
12151241
Log.d(TAG, "onCallConnected getCompositedLayout: $layout")
1242+
binding.ivNetworkSignal.visibility = View.VISIBLE
12161243
webexViewModel.setCompositedLayout(layout)
12171244
webexViewModel.setRemoteVideoRenderMode(callId, webexViewModel.scalingMode)
12181245

@@ -1943,6 +1970,29 @@ class CallControlsFragment : Fragment(), OnClickListener, CallObserverInterface
19431970
activity?.supportFragmentManager?.let { cameraOptionsBottomSheetFragment.show(it, CameraOptionsBottomSheetFragment.TAG) }
19441971
}
19451972

1973+
private fun updateNetworkStatusChange(mediaQualityInfo: Call.MediaQualityInfo) {
1974+
when (mediaQualityInfo) {
1975+
Call.MediaQualityInfo.NetworkLost -> {
1976+
binding.ivNetworkSignal.setImageResource(R.drawable.ic_no_network)
1977+
currentNetworkStatus = NetworkStatus.NoNetwork
1978+
}
1979+
Call.MediaQualityInfo.Good -> {
1980+
binding.ivNetworkSignal.setImageResource(R.drawable.ic_good_network)
1981+
currentNetworkStatus = NetworkStatus.Good
1982+
}
1983+
Call.MediaQualityInfo.PoorUplink -> {
1984+
binding.ivNetworkSignal.setImageResource(R.drawable.ic_poor_network)
1985+
currentNetworkStatus = NetworkStatus.PoorUplink
1986+
}
1987+
Call.MediaQualityInfo.PoorDownlink -> {
1988+
binding.ivNetworkSignal.setImageResource(R.drawable.ic_poor_network)
1989+
currentNetworkStatus = NetworkStatus.PoorDownlink
1990+
}
1991+
Call.MediaQualityInfo.HighCpuUsage -> showDialogWithMessage(requireContext(), R.string.warning, getString(R.string.high_cpu_usage))
1992+
Call.MediaQualityInfo.DeviceLimitation -> showDialogWithMessage(requireContext(), R.string.warning, getString(R.string.device_limitation))
1993+
}
1994+
}
1995+
19461996
class IncomingInfoAdapter(private val incomingCallEvent: (Call?) -> Unit, private val IncomingCallPickEvent: (Call?) -> Unit, private val incomingCallCancelEvent: (Call?) -> Unit) : RecyclerView.Adapter<IncomingInfoViewHolder>() {
19471997
var info: MutableList<IncomingCallInfoModel> = mutableListOf()
19481998

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
@@ -20,4 +20,5 @@ interface CallObserverInterface {
2020
fun onScheduleChanged(call: Call?) {}
2121
fun onCpuHitThreshold() {}
2222
fun onPhotoCaptured(imageData: ByteArray?) {}
23+
fun onMediaQualityInfoChanged(mediaQualityInfo: Call.MediaQualityInfo)
2324
}

app/src/main/java/com/ciscowebex/androidsdk/kitchensink/firebase/KitchenSinkFCMService.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ class KitchenSinkFCMService : FirebaseMessagingService() {
158158
val size = it.data?.size ?: 0
159159
if (size > 0) {
160160
val message = it.data?.get(size - 1)
161-
Log.d(TAG, "last message: ${message?.getTextAsObject()?.getMarkdown()}")
161+
Log.d(TAG, "last message: ${message?.getText()}")
162162

163163
Log.d(TAG, "Fetching person details")
164164
repository.getPerson(Base64Utils.decodeString(notificationData?.data?.personId), CompletionHandler { personResult ->
@@ -217,7 +217,7 @@ class KitchenSinkFCMService : FirebaseMessagingService() {
217217
.setContentIntent(pendingIntent)
218218
.setStyle(
219219
NotificationCompat.BigTextStyle()
220-
.bigText(Html.fromHtml(message?.getTextAsObject()?.getMarkdown().orEmpty(), Html.FROM_HTML_MODE_LEGACY))
220+
.bigText(Html.fromHtml(message?.getText().orEmpty(), Html.FROM_HTML_MODE_LEGACY))
221221
)
222222
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager?
223223

app/src/main/java/com/ciscowebex/androidsdk/kitchensink/messaging/composer/MessageComposerActivity.kt

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ class MessageComposerActivity : AppCompatActivity() {
4848

4949
enum class StyleType {
5050
PLAIN_TEXT,
51-
MARKDOWN_TEXT
51+
MARKDOWN_TEXT,
52+
HTML_TEXT
5253
}
5354

5455
fun getIntent(context: Context, type: ComposerType, id: String, replyParentMessage: ReplyMessageModel?, messageId: String? = null): Intent {
@@ -118,6 +119,9 @@ class MessageComposerActivity : AppCompatActivity() {
118119
R.id.markdownRadioButton -> {
119120
styleType = StyleType.MARKDOWN_TEXT
120121
}
122+
R.id.htmlRadioButton -> {
123+
styleType = StyleType.HTML_TEXT
124+
}
121125
}
122126
}
123127

@@ -261,14 +265,20 @@ class MessageComposerActivity : AppCompatActivity() {
261265
}
262266
}
263267

268+
private fun buildMessageText(message: String) : Message.Text{
269+
return when(styleType){
270+
StyleType.HTML_TEXT -> Message.Text.html(message)
271+
StyleType.MARKDOWN_TEXT -> Message.Text.markdown(message)
272+
else -> {
273+
Message.Text.plain(message)
274+
}
275+
}
276+
}
277+
264278
private fun editMessage(messageId: String) {
265279
val str = binding.message.text.toString()
266280
val messageContent = binding.message.getMessageContent()
267-
val text: Message.Text = if (styleType == StyleType.PLAIN_TEXT) {
268-
Message.Text.plain(str)
269-
} else {
270-
Message.Text.markdown(str, null, null)
271-
}
281+
val text: Message.Text = buildMessageText(str);
272282

273283
messageComposerViewModel.editMessage(messageId, text, messageContent.messageInputMentions)
274284
}
@@ -283,11 +293,11 @@ class MessageComposerActivity : AppCompatActivity() {
283293
messageData = message
284294
val msg = message.getTextAsObject()
285295

286-
msg.getMarkdown()?.let {
287-
messageBodyTextView.text = Html.fromHtml(msg.getMarkdown(), Html.FROM_HTML_MODE_LEGACY)
296+
msg.getHtml()?.let {
297+
messageBodyTextView.text = Html.fromHtml(msg.getHtml(), Html.FROM_HTML_MODE_LEGACY)
288298
} ?: run {
289299
msg.getPlain()?.let {
290-
messageBodyTextView.text = Html.fromHtml(msg.getPlain(), Html.FROM_HTML_MODE_LEGACY)
300+
messageBodyTextView.text = msg.getPlain()
291301
}
292302
}
293303
builder.setView(this.root)
@@ -302,33 +312,27 @@ class MessageComposerActivity : AppCompatActivity() {
302312
private fun postPersonByEmail(email: String, files: ArrayList<LocalFile>?) {
303313
val emailAddress = EmailAddress.fromString(email)
304314
emailAddress?.let {
305-
messageComposerViewModel.postToPerson(emailAddress, binding.message.text.toString(), styleType == StyleType.PLAIN_TEXT, files)
315+
val text: Message.Text = buildMessageText(binding.message.text.toString());
316+
messageComposerViewModel.postToPerson(emailAddress, text, files)
306317
showProgress()
307318
} ?: run {
308319
showDialogWithMessage(this@MessageComposerActivity, R.string.post_message_error, getString(R.string.post_message_email_empty))
309320
}
310321
}
311322

312323
private fun postPersonById(personId: String, files: ArrayList<LocalFile>?) {
313-
messageComposerViewModel.postToPerson(personId, binding.message.text.toString(), styleType == StyleType.PLAIN_TEXT, files)
324+
val text: Message.Text = buildMessageText(binding.message.text.toString());
325+
messageComposerViewModel.postToPerson(personId, text, files)
314326
showProgress()
315327
}
316328

317329
private fun postToSpace(spaceId: String, files: ArrayList<LocalFile>?) {
318330
val messageContent = binding.message.getMessageContent()
319331

320332
var progress = true
321-
333+
val text: Message.Text = buildMessageText(binding.message.text.toString());
322334
replyParentMessage?.let { replyMessage ->
323-
val str = binding.message.text.toString()
324-
325-
val text: Message.Text? = if (styleType == StyleType.PLAIN_TEXT) {
326-
Message.Text.plain(str)
327-
} else {
328-
Message.Text.markdown(str, null, null)
329-
}
330-
331-
text?.let { msgTxt ->
335+
text.let { msgTxt ->
332336
val draft = Message.draft(msgTxt)
333337

334338
messageContent.messageInputMentions?.let { mentionsArray ->
@@ -346,12 +350,9 @@ class MessageComposerActivity : AppCompatActivity() {
346350
draft.setParent(replyMessage.getMessage())
347351

348352
messageComposerViewModel.postMessageDraft(spaceId, draft)
349-
} ?: run {
350-
progress = false
351-
showDialogWithMessage(this@MessageComposerActivity, R.string.post_message_error, getString(R.string.post_message_invalid_message))
352353
}
353354
} ?: run {
354-
messageComposerViewModel.postToSpace(spaceId, binding.message.text.toString(), styleType == StyleType.PLAIN_TEXT, messageContent.messageInputMentions, files)
355+
messageComposerViewModel.postToSpace(spaceId, text, messageContent.messageInputMentions, files)
355356
}
356357

357358
if (progress) {

app/src/main/java/com/ciscowebex/androidsdk/kitchensink/messaging/composer/MessageComposerRepository.kt

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,9 @@ import io.reactivex.Single
1212

1313
open class MessageComposerRepository(private val webex: Webex) {
1414

15-
fun postToSpace(spaceId: String, message: String, plainText: Boolean, mentions: ArrayList<Mention>?, files: ArrayList<LocalFile>?): Observable<Message> {
15+
fun postToSpace(spaceId: String, message: Message.Text, mentions: ArrayList<Mention>?, files: ArrayList<LocalFile>?): Observable<Message> {
1616
return Single.create<Message> { emitter ->
17-
val text: Message.Text? = if (plainText) {
18-
Message.Text.plain(message)
19-
} else {
20-
Message.Text.markdown(message, null, null)
21-
}
22-
webex.messages.postToSpace(spaceId, text, mentions, files, CompletionHandler { result ->
17+
webex.messages.postToSpace(spaceId, message, mentions, files, CompletionHandler { result ->
2318
if (result.isSuccessful) {
2419
emitter.onSuccess(result.data!!)
2520
} else {
@@ -29,14 +24,9 @@ open class MessageComposerRepository(private val webex: Webex) {
2924
}.toObservable()
3025
}
3126

32-
fun postToPerson(email: EmailAddress, message: String, plainText: Boolean, files: ArrayList<LocalFile>?): Observable<Message> {
27+
fun postToPerson(email: EmailAddress, message: Message.Text, files: ArrayList<LocalFile>?): Observable<Message> {
3328
return Single.create<Message> { emitter ->
34-
val text: Message.Text? = if (plainText) {
35-
Message.Text.plain(message)
36-
} else {
37-
Message.Text.markdown(message, null, null)
38-
}
39-
webex.messages.postToPerson(email, text, files, CompletionHandler { result ->
29+
webex.messages.postToPerson(email, message, files, CompletionHandler { result ->
4030
if (result.isSuccessful) {
4131
emitter.onSuccess(result.data!!)
4232
} else {
@@ -46,14 +36,9 @@ open class MessageComposerRepository(private val webex: Webex) {
4636
}.toObservable()
4737
}
4838

49-
fun postToPerson(id: String, message: String, plainText: Boolean, files: ArrayList<LocalFile>?): Observable<Message> {
39+
fun postToPerson(id: String, message: Message.Text, files: ArrayList<LocalFile>?): Observable<Message> {
5040
return Single.create<Message> { emitter ->
51-
val text: Message.Text? = if (plainText) {
52-
Message.Text.plain(message)
53-
} else {
54-
Message.Text.markdown(message, null, null)
55-
}
56-
webex.messages.postToPerson(id, text, files, CompletionHandler { result ->
41+
webex.messages.postToPerson(id, message, files, CompletionHandler { result ->
5742
if (result.isSuccessful) {
5843
emitter.onSuccess(result.data!!)
5944
} else {

app/src/main/java/com/ciscowebex/androidsdk/kitchensink/messaging/composer/MessageComposerViewModel.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,20 @@ class MessageComposerViewModel(private val composerRepo: MessageComposerReposito
4141

4242
val labelAll = "All"
4343

44-
fun postToSpace(spaceId: String, message: String, plainText: Boolean, mentions: ArrayList<Mention>?, files: ArrayList<LocalFile>? = null) {
45-
composerRepo.postToSpace(spaceId, message, plainText, mentions, files).observeOn(AndroidSchedulers.mainThread()).subscribe({ result ->
44+
fun postToSpace(spaceId: String, message: Message.Text, mentions: ArrayList<Mention>?, files: ArrayList<LocalFile>? = null) {
45+
composerRepo.postToSpace(spaceId, message, mentions, files).observeOn(AndroidSchedulers.mainThread()).subscribe({ result ->
4646
_postMessages.postValue(result)
4747
}, { error -> _postMessageError.postValue(error.message) }).autoDispose()
4848
}
4949

50-
fun postToPerson(email: EmailAddress, message: String, plainText: Boolean, files: ArrayList<LocalFile>? = null) {
51-
composerRepo.postToPerson(email, message, plainText, files).observeOn(AndroidSchedulers.mainThread()).subscribe({ result ->
50+
fun postToPerson(email: EmailAddress, message: Message.Text, files: ArrayList<LocalFile>? = null) {
51+
composerRepo.postToPerson(email, message, files).observeOn(AndroidSchedulers.mainThread()).subscribe({ result ->
5252
_postMessages.postValue(result)
5353
}, { error -> _postMessageError.postValue(error.message) }).autoDispose()
5454
}
5555

56-
fun postToPerson(id: String, message: String, plainText: Boolean, files: ArrayList<LocalFile>? = null) {
57-
composerRepo.postToPerson(id, message, plainText, files).observeOn(AndroidSchedulers.mainThread()).subscribe({ result ->
56+
fun postToPerson(id: String, message: Message.Text, files: ArrayList<LocalFile>? = null) {
57+
composerRepo.postToPerson(id, message, files).observeOn(AndroidSchedulers.mainThread()).subscribe({ result ->
5858
Log.d(tag, "postToPersonID result: $result")
5959
_postMessages.postValue(result)
6060
}, { error -> _postMessageError.postValue(error.message) }).autoDispose()

0 commit comments

Comments
 (0)