mirror of
https://github.com/nextcloud/talk-android
synced 2025-07-11 06:44:09 +01:00
Merge pull request #2566 from nextcloud/bugfix/1724followup/improveNotificationSoundHandling
Bugfix/1724followup/improve notification sound handling
This commit is contained in:
commit
25c7d76ec9
@ -22,22 +22,16 @@
|
|||||||
package com.nextcloud.talk.activities
|
package com.nextcloud.talk.activities
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Notification
|
|
||||||
import android.app.NotificationManager
|
|
||||||
import android.app.PendingIntent
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.media.AudioAttributes
|
|
||||||
import android.media.MediaPlayer
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.SystemClock
|
import android.os.Looper
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
import autodagger.AutoInjector
|
import autodagger.AutoInjector
|
||||||
import com.nextcloud.talk.R
|
import com.nextcloud.talk.R
|
||||||
import com.nextcloud.talk.api.NcApi
|
import com.nextcloud.talk.api.NcApi
|
||||||
@ -49,11 +43,8 @@ import com.nextcloud.talk.extensions.loadAvatar
|
|||||||
import com.nextcloud.talk.models.json.conversations.Conversation
|
import com.nextcloud.talk.models.json.conversations.Conversation
|
||||||
import com.nextcloud.talk.models.json.conversations.RoomOverall
|
import com.nextcloud.talk.models.json.conversations.RoomOverall
|
||||||
import com.nextcloud.talk.models.json.participants.Participant
|
import com.nextcloud.talk.models.json.participants.Participant
|
||||||
import com.nextcloud.talk.models.json.participants.ParticipantsOverall
|
|
||||||
import com.nextcloud.talk.utils.ApiUtils
|
import com.nextcloud.talk.utils.ApiUtils
|
||||||
import com.nextcloud.talk.utils.DoNotDisturbUtils.shouldPlaySound
|
|
||||||
import com.nextcloud.talk.utils.NotificationUtils
|
import com.nextcloud.talk.utils.NotificationUtils
|
||||||
import com.nextcloud.talk.utils.NotificationUtils.getCallRingtoneUri
|
|
||||||
import com.nextcloud.talk.utils.ParticipantPermissions
|
import com.nextcloud.talk.utils.ParticipantPermissions
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys
|
import com.nextcloud.talk.utils.bundle.BundleKeys
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CALL_VOICE_ONLY
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CALL_VOICE_ONLY
|
||||||
@ -62,7 +53,6 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM
|
|||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USER_ENTITY
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USER_ENTITY
|
||||||
import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew.hasSpreedFeatureCapability
|
import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew.hasSpreedFeatureCapability
|
||||||
import io.reactivex.Observable
|
|
||||||
import io.reactivex.Observer
|
import io.reactivex.Observer
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.disposables.Disposable
|
import io.reactivex.disposables.Disposable
|
||||||
@ -71,7 +61,6 @@ import kotlinx.android.synthetic.main.call_item.*
|
|||||||
import okhttp3.Cache
|
import okhttp3.Cache
|
||||||
import org.parceler.Parcels
|
import org.parceler.Parcels
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@SuppressLint("LongLogTag")
|
@SuppressLint("LongLogTag")
|
||||||
@ -88,13 +77,14 @@ class CallNotificationActivity : CallBaseActivity() {
|
|||||||
private val disposablesList: MutableList<Disposable> = ArrayList()
|
private val disposablesList: MutableList<Disposable> = ArrayList()
|
||||||
private var originalBundle: Bundle? = null
|
private var originalBundle: Bundle? = null
|
||||||
private var roomToken: String? = null
|
private var roomToken: String? = null
|
||||||
|
private var notificationTimestamp: Int? = null
|
||||||
private var userBeingCalled: User? = null
|
private var userBeingCalled: User? = null
|
||||||
private var credentials: String? = null
|
private var credentials: String? = null
|
||||||
private var currentConversation: Conversation? = null
|
private var currentConversation: Conversation? = null
|
||||||
private var mediaPlayer: MediaPlayer? = null
|
|
||||||
private var leavingScreen = false
|
private var leavingScreen = false
|
||||||
private var handler: Handler? = null
|
private var handler: Handler? = null
|
||||||
private var binding: CallNotificationActivityBinding? = null
|
private var binding: CallNotificationActivityBinding? = null
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
Log.d(TAG, "onCreate")
|
Log.d(TAG, "onCreate")
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -104,6 +94,7 @@ class CallNotificationActivity : CallBaseActivity() {
|
|||||||
hideNavigationIfNoPipAvailable()
|
hideNavigationIfNoPipAvailable()
|
||||||
val extras = intent.extras
|
val extras = intent.extras
|
||||||
roomToken = extras!!.getString(KEY_ROOM_TOKEN, "")
|
roomToken = extras!!.getString(KEY_ROOM_TOKEN, "")
|
||||||
|
notificationTimestamp = extras.getInt(BundleKeys.KEY_NOTIFICATION_TIMESTAMP)
|
||||||
currentConversation = Parcels.unwrap(extras.getParcelable(KEY_ROOM))
|
currentConversation = Parcels.unwrap(extras.getParcelable(KEY_ROOM))
|
||||||
userBeingCalled = extras.getParcelable(KEY_USER_ENTITY)
|
userBeingCalled = extras.getParcelable(KEY_USER_ENTITY)
|
||||||
originalBundle = extras
|
originalBundle = extras
|
||||||
@ -114,9 +105,6 @@ class CallNotificationActivity : CallBaseActivity() {
|
|||||||
} else {
|
} else {
|
||||||
setUpAfterConversationIsKnown()
|
setUpAfterConversationIsKnown()
|
||||||
}
|
}
|
||||||
if (shouldPlaySound()) {
|
|
||||||
playRingtoneSound()
|
|
||||||
}
|
|
||||||
initClickListeners()
|
initClickListeners()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,7 +150,6 @@ class CallNotificationActivity : CallBaseActivity() {
|
|||||||
private fun hangup() {
|
private fun hangup() {
|
||||||
leavingScreen = true
|
leavingScreen = true
|
||||||
dispose()
|
dispose()
|
||||||
endMediaNotifications()
|
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,108 +175,6 @@ class CallNotificationActivity : CallBaseActivity() {
|
|||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkIfAnyParticipantsRemainInRoom() {
|
|
||||||
val apiVersion = ApiUtils.getCallApiVersion(userBeingCalled, intArrayOf(ApiUtils.APIv4, 1))
|
|
||||||
ncApi!!.getPeersForCall(
|
|
||||||
credentials,
|
|
||||||
ApiUtils.getUrlForCall(
|
|
||||||
apiVersion,
|
|
||||||
userBeingCalled!!.baseUrl,
|
|
||||||
currentConversation!!.token
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.repeatWhen { completed: Observable<Any?> ->
|
|
||||||
completed.zipWith(Observable.range(TIMER_START, TIMER_COUNT)) { _: Any?, i: Int? -> i!! }
|
|
||||||
.flatMap { Observable.timer(TIMER_DELAY, TimeUnit.SECONDS) }
|
|
||||||
.takeWhile { !leavingScreen }
|
|
||||||
}
|
|
||||||
.subscribe(object : Observer<ParticipantsOverall> {
|
|
||||||
override fun onSubscribe(d: Disposable) {
|
|
||||||
disposablesList.add(d)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNext(participantsOverall: ParticipantsOverall) {
|
|
||||||
val hasParticipantsInCall: Boolean
|
|
||||||
var inCallOnDifferentDevice = false
|
|
||||||
val participantList = participantsOverall.ocs!!.data
|
|
||||||
hasParticipantsInCall = participantList!!.isNotEmpty()
|
|
||||||
if (hasParticipantsInCall) {
|
|
||||||
for (participant in participantList) {
|
|
||||||
if (participant.calculatedActorType === Participant.ActorType.USERS &&
|
|
||||||
participant.calculatedActorId == userBeingCalled!!.userId
|
|
||||||
) {
|
|
||||||
inCallOnDifferentDevice = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (inCallOnDifferentDevice) {
|
|
||||||
runOnUiThread { hangup() }
|
|
||||||
}
|
|
||||||
if (!hasParticipantsInCall) {
|
|
||||||
showMissedCallNotification()
|
|
||||||
runOnUiThread { hangup() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
|
||||||
Log.e(TAG, "error while getPeersForCall", e)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onComplete() {
|
|
||||||
showMissedCallNotification()
|
|
||||||
runOnUiThread { hangup() }
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showMissedCallNotification() {
|
|
||||||
val mNotifyManager: NotificationManager?
|
|
||||||
val mBuilder: NotificationCompat.Builder?
|
|
||||||
|
|
||||||
mNotifyManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
||||||
mBuilder = NotificationCompat.Builder(
|
|
||||||
context,
|
|
||||||
NotificationUtils.NotificationChannels
|
|
||||||
.NOTIFICATION_CHANNEL_MESSAGES_V4.name
|
|
||||||
)
|
|
||||||
|
|
||||||
val notification: Notification = mBuilder
|
|
||||||
.setContentTitle(
|
|
||||||
String.format(resources.getString(R.string.nc_missed_call), currentConversation!!.displayName)
|
|
||||||
)
|
|
||||||
.setSmallIcon(R.drawable.ic_baseline_phone_missed_24)
|
|
||||||
.setOngoing(false)
|
|
||||||
.setAutoCancel(true)
|
|
||||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
|
||||||
.setContentIntent(getIntentToOpenConversation())
|
|
||||||
.build()
|
|
||||||
|
|
||||||
val notificationId: Int = SystemClock.uptimeMillis().toInt()
|
|
||||||
mNotifyManager.notify(notificationId, notification)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getIntentToOpenConversation(): PendingIntent? {
|
|
||||||
val bundle = Bundle()
|
|
||||||
val intent = Intent(context, MainActivity::class.java)
|
|
||||||
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
|
|
||||||
|
|
||||||
bundle.putString(KEY_ROOM_TOKEN, currentConversation?.token)
|
|
||||||
bundle.putParcelable(KEY_USER_ENTITY, userBeingCalled)
|
|
||||||
bundle.putBoolean(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)
|
|
||||||
|
|
||||||
intent.putExtras(bundle)
|
|
||||||
|
|
||||||
val requestCode = System.currentTimeMillis().toInt()
|
|
||||||
val intentFlag: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
||||||
PendingIntent.FLAG_MUTABLE
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
return PendingIntent.getActivity(context, requestCode, intent, intentFlag)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber")
|
||||||
private fun handleFromNotification() {
|
private fun handleFromNotification() {
|
||||||
val apiVersion = ApiUtils.getConversationApiVersion(
|
val apiVersion = ApiUtils.getConversationApiVersion(
|
||||||
@ -353,18 +238,25 @@ class CallNotificationActivity : CallBaseActivity() {
|
|||||||
} else {
|
} else {
|
||||||
binding!!.avatarImageView.setImageResource(R.drawable.ic_circular_group)
|
binding!!.avatarImageView.setImageResource(R.drawable.ic_circular_group)
|
||||||
}
|
}
|
||||||
checkIfAnyParticipantsRemainInRoom()
|
|
||||||
|
val notificationHandler = Handler(Looper.getMainLooper())
|
||||||
|
notificationHandler.post(object : Runnable {
|
||||||
|
override fun run() {
|
||||||
|
if (NotificationUtils.isNotificationVisible(context, notificationTimestamp!!.toInt())) {
|
||||||
|
notificationHandler.postDelayed(this, 1000)
|
||||||
|
} else {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
showAnswerControls()
|
showAnswerControls()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun endMediaNotifications() {
|
override fun onStop() {
|
||||||
if (mediaPlayer != null) {
|
val notificationManager = NotificationManagerCompat.from(context)
|
||||||
if (mediaPlayer!!.isPlaying) {
|
notificationManager.cancel(notificationTimestamp!!)
|
||||||
mediaPlayer!!.stop()
|
super.onStop()
|
||||||
}
|
|
||||||
mediaPlayer!!.release()
|
|
||||||
mediaPlayer = null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override fun onDestroy() {
|
public override fun onDestroy() {
|
||||||
@ -374,7 +266,6 @@ class CallNotificationActivity : CallBaseActivity() {
|
|||||||
handler = null
|
handler = null
|
||||||
}
|
}
|
||||||
dispose()
|
dispose()
|
||||||
endMediaNotifications()
|
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,26 +277,6 @@ class CallNotificationActivity : CallBaseActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun playRingtoneSound() {
|
|
||||||
val ringtoneUri = getCallRingtoneUri(applicationContext, appPreferences)
|
|
||||||
if (ringtoneUri != null) {
|
|
||||||
mediaPlayer = MediaPlayer()
|
|
||||||
try {
|
|
||||||
mediaPlayer!!.setDataSource(this, ringtoneUri)
|
|
||||||
mediaPlayer!!.isLooping = true
|
|
||||||
val audioAttributes = AudioAttributes.Builder()
|
|
||||||
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
|
||||||
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
|
|
||||||
.build()
|
|
||||||
mediaPlayer!!.setAudioAttributes(audioAttributes)
|
|
||||||
mediaPlayer!!.setOnPreparedListener { mediaPlayer!!.start() }
|
|
||||||
mediaPlayer!!.prepareAsync()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
Log.e(TAG, "Failed to set data source")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||||
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration) {
|
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration) {
|
||||||
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
|
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
|
||||||
@ -433,9 +304,6 @@ class CallNotificationActivity : CallBaseActivity() {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "CallNotificationActivity"
|
const val TAG = "CallNotificationActivity"
|
||||||
const val TIMER_START = 1
|
|
||||||
const val TIMER_COUNT = 12
|
|
||||||
const val TIMER_DELAY: Long = 5
|
|
||||||
const val GET_ROOM_RETRY_COUNT: Long = 3
|
const val GET_ROOM_RETRY_COUNT: Long = 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,10 +24,8 @@
|
|||||||
package com.nextcloud.talk.jobs
|
package com.nextcloud.talk.jobs
|
||||||
|
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import android.app.NotificationManager
|
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Context.NOTIFICATION_SERVICE
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.media.AudioAttributes
|
import android.media.AudioAttributes
|
||||||
@ -85,6 +83,7 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FROM_NOTIFICATION_START_CA
|
|||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_MESSAGE_ID
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_MESSAGE_ID
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_ID
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_ID
|
||||||
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_TIMESTAMP
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SYSTEM_NOTIFICATION_ID
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SYSTEM_NOTIFICATION_ID
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USER_ENTITY
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USER_ENTITY
|
||||||
@ -212,6 +211,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
|
|||||||
val fullScreenIntent = Intent(context, CallNotificationActivity::class.java)
|
val fullScreenIntent = Intent(context, CallNotificationActivity::class.java)
|
||||||
val bundle = Bundle()
|
val bundle = Bundle()
|
||||||
bundle.putString(KEY_ROOM_TOKEN, pushMessage.id)
|
bundle.putString(KEY_ROOM_TOKEN, pushMessage.id)
|
||||||
|
bundle.putInt(KEY_NOTIFICATION_TIMESTAMP, pushMessage.timestamp.toInt())
|
||||||
bundle.putParcelable(KEY_USER_ENTITY, signatureVerification.user)
|
bundle.putParcelable(KEY_USER_ENTITY, signatureVerification.user)
|
||||||
bundle.putBoolean(KEY_FROM_NOTIFICATION_START_CALL, true)
|
bundle.putBoolean(KEY_FROM_NOTIFICATION_START_CALL, true)
|
||||||
fullScreenIntent.putExtras(bundle)
|
fullScreenIntent.putExtras(bundle)
|
||||||
@ -231,8 +231,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
|
|||||||
)
|
)
|
||||||
|
|
||||||
val soundUri = getCallRingtoneUri(applicationContext, appPreferences)
|
val soundUri = getCallRingtoneUri(applicationContext, appPreferences)
|
||||||
val notificationChannelId = NotificationUtils
|
val notificationChannelId = NotificationUtils.NotificationChannels.NOTIFICATION_CHANNEL_CALLS_V4.name
|
||||||
.NotificationChannels.NOTIFICATION_CHANNEL_CALLS_V4.name
|
|
||||||
val uri = Uri.parse(signatureVerification.user!!.baseUrl)
|
val uri = Uri.parse(signatureVerification.user!!.baseUrl)
|
||||||
val baseUrl = uri.host
|
val baseUrl = uri.host
|
||||||
|
|
||||||
@ -245,7 +244,9 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
|
|||||||
.setShowWhen(true)
|
.setShowWhen(true)
|
||||||
.setWhen(pushMessage.timestamp)
|
.setWhen(pushMessage.timestamp)
|
||||||
.setContentTitle(EmojiCompat.get().process(pushMessage.subject))
|
.setContentTitle(EmojiCompat.get().process(pushMessage.subject))
|
||||||
.setAutoCancel(true)
|
// auto cancel is set to false because notification (including sound) should continue while
|
||||||
|
// CallNotificationActivity is active
|
||||||
|
.setAutoCancel(false)
|
||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
.setContentIntent(fullScreenPendingIntent)
|
.setContentIntent(fullScreenPendingIntent)
|
||||||
.setFullScreenIntent(fullScreenPendingIntent, true)
|
.setFullScreenIntent(fullScreenPendingIntent, true)
|
||||||
@ -255,7 +256,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
|
|||||||
|
|
||||||
sendNotification(pushMessage.timestamp.toInt(), notification)
|
sendNotification(pushMessage.timestamp.toInt(), notification)
|
||||||
|
|
||||||
checkIfCallIsActive(signatureVerification, pushMessage)
|
checkIfCallIsActive(signatureVerification)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initNcApiAndCredentials() {
|
private fun initNcApiAndCredentials() {
|
||||||
@ -660,10 +661,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
|
|||||||
notificationManager.cancel(notificationId)
|
notificationManager.cancel(notificationId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkIfCallIsActive(
|
private fun checkIfCallIsActive(signatureVerification: SignatureVerification) {
|
||||||
signatureVerification: SignatureVerification,
|
|
||||||
decryptedPushMessage: DecryptedPushMessage
|
|
||||||
) {
|
|
||||||
Log.d(TAG, "checkIfCallIsActive")
|
Log.d(TAG, "checkIfCallIsActive")
|
||||||
var hasParticipantsInCall = true
|
var hasParticipantsInCall = true
|
||||||
var inCallOnDifferentDevice = false
|
var inCallOnDifferentDevice = false
|
||||||
@ -680,7 +678,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
|
|||||||
ApiUtils.getUrlForCall(
|
ApiUtils.getUrlForCall(
|
||||||
apiVersion,
|
apiVersion,
|
||||||
signatureVerification.user!!.baseUrl,
|
signatureVerification.user!!.baseUrl,
|
||||||
decryptedPushMessage.id
|
pushMessage.id
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.repeatWhen { completed ->
|
.repeatWhen { completed ->
|
||||||
@ -707,16 +705,19 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
|
|||||||
}
|
}
|
||||||
if (inCallOnDifferentDevice) {
|
if (inCallOnDifferentDevice) {
|
||||||
Log.d(TAG, "inCallOnDifferentDevice is true")
|
Log.d(TAG, "inCallOnDifferentDevice is true")
|
||||||
removeNotification(decryptedPushMessage.timestamp.toInt())
|
removeNotification(pushMessage.timestamp.toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasParticipantsInCall) {
|
if (!hasParticipantsInCall) {
|
||||||
showMissedCallNotification()
|
showMissedCallNotification()
|
||||||
Log.d(TAG, "no participants in call")
|
Log.d(TAG, "no participants in call")
|
||||||
removeNotification(decryptedPushMessage.timestamp.toInt())
|
removeNotification(pushMessage.timestamp.toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
isCallNotificationVisible = isCallNotificationVisible(decryptedPushMessage)
|
isCallNotificationVisible = NotificationUtils.isNotificationVisible(
|
||||||
|
context,
|
||||||
|
pushMessage.timestamp.toInt()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
override fun onError(e: Throwable) {
|
||||||
@ -730,12 +731,18 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
|
|||||||
showMissedCallNotification()
|
showMissedCallNotification()
|
||||||
}
|
}
|
||||||
|
|
||||||
removeNotification(decryptedPushMessage.timestamp.toInt())
|
removeNotification(pushMessage.timestamp.toInt())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showMissedCallNotification() {
|
fun showMissedCallNotification() {
|
||||||
|
val isOngoingCallNotificationVisible = NotificationUtils.isNotificationVisible(
|
||||||
|
context,
|
||||||
|
pushMessage.timestamp.toInt()
|
||||||
|
)
|
||||||
|
|
||||||
|
if (isOngoingCallNotificationVisible) {
|
||||||
val apiVersion = ApiUtils.getConversationApiVersion(
|
val apiVersion = ApiUtils.getConversationApiVersion(
|
||||||
signatureVerification.user,
|
signatureVerification.user,
|
||||||
intArrayOf(
|
intArrayOf(
|
||||||
@ -796,6 +803,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun getIntentToOpenConversation(): PendingIntent? {
|
private fun getIntentToOpenConversation(): PendingIntent? {
|
||||||
val bundle = Bundle()
|
val bundle = Bundle()
|
||||||
@ -817,20 +825,6 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
|
|||||||
return PendingIntent.getActivity(context, requestCode, intent, intentFlag)
|
return PendingIntent.getActivity(context, requestCode, intent, intentFlag)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isCallNotificationVisible(decryptedPushMessage: DecryptedPushMessage): Boolean {
|
|
||||||
var isVisible = false
|
|
||||||
|
|
||||||
val notificationManager = context!!.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
|
||||||
val notifications = notificationManager.activeNotifications
|
|
||||||
for (notification in notifications) {
|
|
||||||
if (notification.id == decryptedPushMessage.timestamp.toInt()) {
|
|
||||||
isVisible = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return isVisible
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val TAG = NotificationWorker::class.simpleName
|
val TAG = NotificationWorker::class.simpleName
|
||||||
private const val CHAT = "chat"
|
private const val CHAT = "chat"
|
||||||
|
@ -25,7 +25,6 @@ import android.app.NotificationManager
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.media.AudioManager
|
import android.media.AudioManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Vibrator
|
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||||
|
|
||||||
@ -60,28 +59,4 @@ object DoNotDisturbUtils {
|
|||||||
|
|
||||||
return shouldPlaySound
|
return shouldPlaySound
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hasVibrator(context: Context?): Boolean {
|
|
||||||
val vibrator = context?.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
|
||||||
return vibrator.hasVibrator()
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmOverloads
|
|
||||||
fun shouldVibrate(
|
|
||||||
context: Context? = NextcloudTalkApplication.sharedApplication?.applicationContext,
|
|
||||||
vibrate: Boolean
|
|
||||||
): Boolean {
|
|
||||||
|
|
||||||
if (hasVibrator(context)) {
|
|
||||||
val audioManager = context?.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
|
||||||
|
|
||||||
return if (vibrate) {
|
|
||||||
audioManager.ringerMode != AudioManager.RINGER_MODE_SILENT
|
|
||||||
} else {
|
|
||||||
audioManager.ringerMode == AudioManager.RINGER_MODE_VIBRATE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -274,6 +274,24 @@ object NotificationUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isNotificationVisible(
|
||||||
|
context: Context?,
|
||||||
|
notificationId: Int
|
||||||
|
): Boolean {
|
||||||
|
|
||||||
|
var isVisible = false
|
||||||
|
|
||||||
|
val notificationManager = context!!.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
val notifications = notificationManager.activeNotifications
|
||||||
|
for (notification in notifications) {
|
||||||
|
if (notification.id == notificationId) {
|
||||||
|
isVisible = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isVisible
|
||||||
|
}
|
||||||
|
|
||||||
private fun getRingtoneUri(
|
private fun getRingtoneUri(
|
||||||
context: Context,
|
context: Context,
|
||||||
ringtonePreferencesString: String?,
|
ringtonePreferencesString: String?,
|
||||||
|
@ -66,6 +66,7 @@ object BundleKeys {
|
|||||||
const val KEY_ACCOUNT = "KEY_ACCOUNT"
|
const val KEY_ACCOUNT = "KEY_ACCOUNT"
|
||||||
const val KEY_FILE_ID = "KEY_FILE_ID"
|
const val KEY_FILE_ID = "KEY_FILE_ID"
|
||||||
const val KEY_NOTIFICATION_ID = "KEY_NOTIFICATION_ID"
|
const val KEY_NOTIFICATION_ID = "KEY_NOTIFICATION_ID"
|
||||||
|
const val KEY_NOTIFICATION_TIMESTAMP = "KEY_NOTIFICATION_TIMESTAMP"
|
||||||
const val KEY_SHARED_TEXT = "KEY_SHARED_TEXT"
|
const val KEY_SHARED_TEXT = "KEY_SHARED_TEXT"
|
||||||
const val KEY_GEOCODING_QUERY = "KEY_GEOCODING_QUERY"
|
const val KEY_GEOCODING_QUERY = "KEY_GEOCODING_QUERY"
|
||||||
const val KEY_META_DATA = "KEY_META_DATA"
|
const val KEY_META_DATA = "KEY_META_DATA"
|
||||||
|
@ -24,7 +24,6 @@ import android.app.NotificationManager;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Vibrator;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -32,7 +31,6 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
public class DoNotDisturbUtilsTest {
|
public class DoNotDisturbUtilsTest {
|
||||||
@ -46,18 +44,14 @@ public class DoNotDisturbUtilsTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private AudioManager audioManager;
|
private AudioManager audioManager;
|
||||||
|
|
||||||
@Mock
|
|
||||||
private Vibrator vibrator;
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
MockitoAnnotations.openMocks(this);
|
MockitoAnnotations.openMocks(this);
|
||||||
when(context.getSystemService(Context.NOTIFICATION_SERVICE)).thenReturn(notificationManager);
|
when(context.getSystemService(Context.NOTIFICATION_SERVICE)).thenReturn(notificationManager);
|
||||||
when(context.getSystemService(Context.AUDIO_SERVICE)).thenReturn(audioManager);
|
when(context.getSystemService(Context.AUDIO_SERVICE)).thenReturn(audioManager);
|
||||||
when(context.getSystemService(Context.VIBRATOR_SERVICE)).thenReturn(vibrator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldPlaySound_givenAndroidMAndInterruptionFilterNone_assertReturnsFalse() {
|
public void shouldPlaySound_givenAndroidMAndInterruptionFilterNone_assertReturnsFalse() {
|
||||||
DoNotDisturbUtils.INSTANCE.setTestingBuildVersion(Build.VERSION_CODES.M);
|
DoNotDisturbUtils.INSTANCE.setTestingBuildVersion(Build.VERSION_CODES.M);
|
||||||
@ -77,32 +71,4 @@ public class DoNotDisturbUtilsTest {
|
|||||||
assertFalse("shouldPlaySound incorrectly returned true",
|
assertFalse("shouldPlaySound incorrectly returned true",
|
||||||
DoNotDisturbUtils.INSTANCE.shouldPlaySound(context));
|
DoNotDisturbUtils.INSTANCE.shouldPlaySound(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldVibrate_givenNoVibrator_assertReturnsFalse() {
|
|
||||||
when(vibrator.hasVibrator()).thenReturn(false);
|
|
||||||
|
|
||||||
assertFalse("shouldVibrate returned true despite no vibrator",
|
|
||||||
DoNotDisturbUtils.INSTANCE.shouldVibrate(context, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldVibrate_givenVibratorAndRingerModeNormal_assertReturnsTrue() {
|
|
||||||
when(vibrator.hasVibrator()).thenReturn(true);
|
|
||||||
|
|
||||||
when(audioManager.getRingerMode()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
|
|
||||||
|
|
||||||
assertTrue("shouldVibrate incorrectly returned false",
|
|
||||||
DoNotDisturbUtils.INSTANCE.shouldVibrate(context, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldVibrate_givenVibratorAndRingerModeSilent_assertReturnsFalse() {
|
|
||||||
when(vibrator.hasVibrator()).thenReturn(true);
|
|
||||||
|
|
||||||
when(audioManager.getRingerMode()).thenReturn(AudioManager.RINGER_MODE_SILENT);
|
|
||||||
|
|
||||||
assertFalse("shouldVibrate returned true despite ringer mode set to silent",
|
|
||||||
DoNotDisturbUtils.INSTANCE.shouldVibrate(context, true));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user