فهرست منبع

remove ringtone logic (only make it depend on notification!)

this commit removes the logic to play the ringtone in CallNotificationActivity. Playing ringtone should only be controlled by the notification channel from OS!

furthermore the checks if a call is stopped or is still ongoing etc was removed from CallNotificationActivity. Instead the CallNotificationActivity now is completely dependent on the notification. If the notification is canceled, the Activity stops. If the Notification is ongoing and hangup of accept call is clicked, then the notification is canceled (including the ringtone).

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
Marcel Hibbe 2 سال پیش
والد
کامیت
9c4b0a00c6

+ 22 - 153
app/src/main/java/com/nextcloud/talk/activities/CallNotificationActivity.kt

@@ -22,22 +22,15 @@
 package com.nextcloud.talk.activities
 
 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.res.Configuration
-import android.media.AudioAttributes
-import android.media.MediaPlayer
 import android.os.Build
 import android.os.Bundle
 import android.os.Handler
-import android.os.SystemClock
 import android.util.Log
 import android.view.View
 import androidx.annotation.RequiresApi
-import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
 import autodagger.AutoInjector
 import com.nextcloud.talk.R
 import com.nextcloud.talk.api.NcApi
@@ -49,11 +42,8 @@ import com.nextcloud.talk.extensions.loadAvatar
 import com.nextcloud.talk.models.json.conversations.Conversation
 import com.nextcloud.talk.models.json.conversations.RoomOverall
 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.DoNotDisturbUtils.shouldPlaySound
 import com.nextcloud.talk.utils.NotificationUtils
-import com.nextcloud.talk.utils.NotificationUtils.getCallRingtoneUri
 import com.nextcloud.talk.utils.ParticipantPermissions
 import com.nextcloud.talk.utils.bundle.BundleKeys
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CALL_VOICE_ONLY
@@ -62,7 +52,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_USER_ENTITY
 import com.nextcloud.talk.utils.database.user.CapabilitiesUtilNew.hasSpreedFeatureCapability
-import io.reactivex.Observable
 import io.reactivex.Observer
 import io.reactivex.android.schedulers.AndroidSchedulers
 import io.reactivex.disposables.Disposable
@@ -71,8 +60,8 @@ import kotlinx.android.synthetic.main.call_item.*
 import okhttp3.Cache
 import org.parceler.Parcels
 import java.io.IOException
-import java.util.concurrent.TimeUnit
 import javax.inject.Inject
+import kotlin.concurrent.thread
 
 @SuppressLint("LongLogTag")
 @AutoInjector(NextcloudTalkApplication::class)
@@ -88,13 +77,14 @@ class CallNotificationActivity : CallBaseActivity() {
     private val disposablesList: MutableList<Disposable> = ArrayList()
     private var originalBundle: Bundle? = null
     private var roomToken: String? = null
+    private var notificationTimestamp: Int? = null
     private var userBeingCalled: User? = null
     private var credentials: String? = null
     private var currentConversation: Conversation? = null
-    private var mediaPlayer: MediaPlayer? = null
     private var leavingScreen = false
     private var handler: Handler? = null
     private var binding: CallNotificationActivityBinding? = null
+
     override fun onCreate(savedInstanceState: Bundle?) {
         Log.d(TAG, "onCreate")
         super.onCreate(savedInstanceState)
@@ -104,6 +94,7 @@ class CallNotificationActivity : CallBaseActivity() {
         hideNavigationIfNoPipAvailable()
         val extras = intent.extras
         roomToken = extras!!.getString(KEY_ROOM_TOKEN, "")
+        notificationTimestamp = extras.getInt(BundleKeys.KEY_NOTIFICATION_TIMESTAMP)
         currentConversation = Parcels.unwrap(extras.getParcelable(KEY_ROOM))
         userBeingCalled = extras.getParcelable(KEY_USER_ENTITY)
         originalBundle = extras
@@ -114,9 +105,6 @@ class CallNotificationActivity : CallBaseActivity() {
         } else {
             setUpAfterConversationIsKnown()
         }
-        if (shouldPlaySound()) {
-            playRingtoneSound()
-        }
         initClickListeners()
     }
 
@@ -162,7 +150,6 @@ class CallNotificationActivity : CallBaseActivity() {
     private fun hangup() {
         leavingScreen = true
         dispose()
-        endMediaNotifications()
         finish()
     }
 
@@ -188,108 +175,6 @@ class CallNotificationActivity : CallBaseActivity() {
         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")
     private fun handleFromNotification() {
         val apiVersion = ApiUtils.getConversationApiVersion(
@@ -353,18 +238,26 @@ class CallNotificationActivity : CallBaseActivity() {
         } else {
             binding!!.avatarImageView.setImageResource(R.drawable.ic_circular_group)
         }
-        checkIfAnyParticipantsRemainInRoom()
-        showAnswerControls()
-    }
 
-    private fun endMediaNotifications() {
-        if (mediaPlayer != null) {
-            if (mediaPlayer!!.isPlaying) {
-                mediaPlayer!!.stop()
+        thread(start = true) {
+            var isNotificationOpen = true
+            while (isNotificationOpen) {
+                Thread.sleep(1000)
+                Log.d(TAG, ".")
+                if (!NotificationUtils.isNotificationVisible(context, notificationTimestamp!!.toInt())) {
+                    isNotificationOpen = false
+                    finish()
+                }
             }
-            mediaPlayer!!.release()
-            mediaPlayer = null
         }
+
+        showAnswerControls()
+    }
+
+    override fun onStop() {
+        val notificationManager = NotificationManagerCompat.from(context)
+        notificationManager.cancel(notificationTimestamp!!)
+        super.onStop()
     }
 
     public override fun onDestroy() {
@@ -374,7 +267,6 @@ class CallNotificationActivity : CallBaseActivity() {
             handler = null
         }
         dispose()
-        endMediaNotifications()
         super.onDestroy()
     }
 
@@ -386,26 +278,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)
     override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration) {
         super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
@@ -433,9 +305,6 @@ class CallNotificationActivity : CallBaseActivity() {
 
     companion object {
         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
     }
 }

+ 10 - 20
app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt

@@ -24,10 +24,8 @@
 package com.nextcloud.talk.jobs
 
 import android.app.Notification
-import android.app.NotificationManager
 import android.app.PendingIntent
 import android.content.Context
-import android.content.Context.NOTIFICATION_SERVICE
 import android.content.Intent
 import android.graphics.Bitmap
 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_MESSAGE_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_SYSTEM_NOTIFICATION_ID
 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 bundle = Bundle()
         bundle.putString(KEY_ROOM_TOKEN, pushMessage.id)
+        bundle.putInt(KEY_NOTIFICATION_TIMESTAMP, pushMessage.timestamp.toInt())
         bundle.putParcelable(KEY_USER_ENTITY, signatureVerification.user)
         bundle.putBoolean(KEY_FROM_NOTIFICATION_START_CALL, true)
         fullScreenIntent.putExtras(bundle)
@@ -231,8 +231,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
         )
 
         val soundUri = getCallRingtoneUri(applicationContext, appPreferences)
-        val notificationChannelId = NotificationUtils
-            .NotificationChannels.NOTIFICATION_CHANNEL_CALLS_V4.name
+        val notificationChannelId = NotificationUtils.NotificationChannels.NOTIFICATION_CHANNEL_CALLS_V4.name
         val uri = Uri.parse(signatureVerification.user!!.baseUrl)
         val baseUrl = uri.host
 
@@ -245,7 +244,9 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
                 .setShowWhen(true)
                 .setWhen(pushMessage.timestamp)
                 .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)
                 .setContentIntent(fullScreenPendingIntent)
                 .setFullScreenIntent(fullScreenPendingIntent, true)
@@ -716,7 +717,10 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
                         removeNotification(decryptedPushMessage.timestamp.toInt())
                     }
 
-                    isCallNotificationVisible = isCallNotificationVisible(decryptedPushMessage)
+                    isCallNotificationVisible = NotificationUtils.isNotificationVisible(
+                        context,
+                        decryptedPushMessage.timestamp.toInt()
+                    )
                 }
 
                 override fun onError(e: Throwable) {
@@ -817,20 +821,6 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
         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 {
         val TAG = NotificationWorker::class.simpleName
         private const val CHAT = "chat"

+ 18 - 0
app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt

@@ -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(
         context: Context,
         ringtonePreferencesString: String?,

+ 1 - 0
app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt

@@ -66,6 +66,7 @@ object BundleKeys {
     const val KEY_ACCOUNT = "KEY_ACCOUNT"
     const val KEY_FILE_ID = "KEY_FILE_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_GEOCODING_QUERY = "KEY_GEOCODING_QUERY"
     const val KEY_META_DATA = "KEY_META_DATA"