Merge pull request #2566 from nextcloud/bugfix/1724followup/improveNotificationSoundHandling

Bugfix/1724followup/improve notification sound handling
This commit is contained in:
Tim Krüger 2022-12-07 14:52:37 +01:00 committed by GitHub
commit 25c7d76ec9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 114 additions and 292 deletions

View File

@ -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
} }
} }

View File

@ -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,71 +731,78 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
showMissedCallNotification() showMissedCallNotification()
} }
removeNotification(decryptedPushMessage.timestamp.toInt()) removeNotification(pushMessage.timestamp.toInt())
} }
}) })
} }
fun showMissedCallNotification() { fun showMissedCallNotification() {
val apiVersion = ApiUtils.getConversationApiVersion( val isOngoingCallNotificationVisible = NotificationUtils.isNotificationVisible(
signatureVerification.user, context,
intArrayOf( pushMessage.timestamp.toInt()
ApiUtils.APIv4,
ApiUtils.APIv3, 1
)
) )
ncApi.getRoom(
credentials, if (isOngoingCallNotificationVisible) {
ApiUtils.getUrlForRoom( val apiVersion = ApiUtils.getConversationApiVersion(
apiVersion, signatureVerification.user?.baseUrl, signatureVerification.user,
pushMessage.id intArrayOf(
ApiUtils.APIv4,
ApiUtils.APIv3, 1
)
) )
) ncApi.getRoom(
.subscribeOn(Schedulers.io()) credentials,
.retry(GET_ROOM_RETRY_COUNT) ApiUtils.getUrlForRoom(
.observeOn(AndroidSchedulers.mainThread()) apiVersion, signatureVerification.user?.baseUrl,
.subscribe(object : Observer<RoomOverall> { pushMessage.id
override fun onSubscribe(d: Disposable) { )
// unused atm )
} .subscribeOn(Schedulers.io())
.retry(GET_ROOM_RETRY_COUNT)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Observer<RoomOverall> {
override fun onSubscribe(d: Disposable) {
// unused atm
}
override fun onNext(roomOverall: RoomOverall) { override fun onNext(roomOverall: RoomOverall) {
val currentConversation = roomOverall.ocs!!.data val currentConversation = roomOverall.ocs!!.data
val notificationBuilder: NotificationCompat.Builder? val notificationBuilder: NotificationCompat.Builder?
notificationBuilder = NotificationCompat.Builder( notificationBuilder = NotificationCompat.Builder(
context!!, context!!,
NotificationUtils.NotificationChannels NotificationUtils.NotificationChannels
.NOTIFICATION_CHANNEL_MESSAGES_V4.name .NOTIFICATION_CHANNEL_MESSAGES_V4.name
)
val notification: Notification = notificationBuilder
.setContentTitle(
String.format(
context!!.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() val notification: Notification = notificationBuilder
notificationManager.notify(notificationId, notification) .setContentTitle(
Log.d(TAG, "'you missed a call' notification was created") String.format(
} context!!.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()
override fun onError(e: Throwable) { val notificationId: Int = SystemClock.uptimeMillis().toInt()
Log.e(TAG, "An error occurred while fetching room for the 'missed call' notification", e) notificationManager.notify(notificationId, notification)
} Log.d(TAG, "'you missed a call' notification was created")
}
override fun onComplete() { override fun onError(e: Throwable) {
// unused atm Log.e(TAG, "An error occurred while fetching room for the 'missed call' notification", e)
} }
})
override fun onComplete() {
// unused atm
}
})
}
} }
private fun getIntentToOpenConversation(): PendingIntent? { private fun getIntentToOpenConversation(): PendingIntent? {
@ -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"

View File

@ -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
}
} }

View File

@ -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?,

View File

@ -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"

View File

@ -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));
}
} }