diff --git a/app/build.gradle b/app/build.gradle
index c886b858bc..7ae925b437 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -304,7 +304,7 @@ dependencies {
implementation 'androidx.media3:media3-ui:1.4.0'
implementation 'org.conscrypt:conscrypt-android:2.5.2'
implementation 'org.signal:aesgcmprovider:0.0.3'
- implementation 'io.github.webrtc-sdk:android:125.6422.04'
+ implementation 'io.github.webrtc-sdk:android:125.6422.06.1'
implementation "me.leolin:ShortcutBadger:1.1.16"
implementation 'se.emilsjolander:stickylistheaders:2.7.0'
implementation 'com.jpardogo.materialtabstrip:library:1.0.9'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1b0f6a7b13..af7e8bfca5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -37,12 +37,14 @@
+
+
-
+
diff --git a/app/src/main/java/org/thoughtcrime/securesms/calls/WebRtcCallActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/calls/WebRtcCallActivity.kt
index 9fdc6b1063..e6c91800e4 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/calls/WebRtcCallActivity.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/calls/WebRtcCallActivity.kt
@@ -262,7 +262,7 @@ class WebRtcCallActivity : PassphraseRequiredActionBarActivity() {
Orientation.REVERSED_LANDSCAPE -> 90f
else -> 0f
}
-
+R.drawable.ic_baseline_call_24
userAvatar.animate().cancel()
userAvatar.animate().rotation(rotation).start()
contactAvatar.animate().cancel()
diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt b/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt
index 91caa7a878..8567644514 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt
@@ -1,5 +1,7 @@
package org.thoughtcrime.securesms.service
+import android.app.ForegroundServiceStartNotAllowedException
+import android.app.KeyguardManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
@@ -10,6 +12,7 @@ import android.content.pm.PackageManager
import android.content.pm.ServiceInfo
import android.media.AudioManager
import android.os.Build
+import android.os.PowerManager
import android.os.ResultReceiver
import android.telephony.TelephonyManager
import androidx.core.app.ServiceCompat
@@ -22,6 +25,7 @@ import dagger.hilt.android.AndroidEntryPoint
import org.session.libsession.messaging.calls.CallMessageType
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.FutureTaskListener
+import org.session.libsession.utilities.NonTranslatableStringConstants
import org.session.libsession.utilities.recipients.Recipient
import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.calls.WebRtcCallActivity
@@ -32,6 +36,7 @@ import org.thoughtcrime.securesms.util.CallNotificationBuilder.Companion.TYPE_IN
import org.thoughtcrime.securesms.util.CallNotificationBuilder.Companion.TYPE_INCOMING_PRE_OFFER
import org.thoughtcrime.securesms.util.CallNotificationBuilder.Companion.TYPE_INCOMING_RINGING
import org.thoughtcrime.securesms.util.CallNotificationBuilder.Companion.TYPE_OUTGOING_RINGING
+import org.thoughtcrime.securesms.util.CallNotificationBuilder.Companion.WEBRTC_NOTIFICATION
import org.thoughtcrime.securesms.webrtc.AudioManagerCommand
import org.thoughtcrime.securesms.webrtc.CallManager
import org.thoughtcrime.securesms.webrtc.CallViewModel
@@ -328,6 +333,54 @@ class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener {
registerUncaughtExceptionHandler()
networkChangedReceiver = NetworkChangeReceiver(::networkChange)
networkChangedReceiver!!.register(this)
+
+ Log.w("ACL", "Lesssgo!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
+ //if (appIsBackground(this)) {
+// ServiceCompat.startForeground(this,
+// CallNotificationBuilder.WEBRTC_NOTIFICATION,
+// CallNotificationBuilder.getFirstCallNotification(this, "Initialising"),
+// if (Build.VERSION.SDK_INT >= 30) ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL else 0
+// )
+
+ // Get the KeyguardManager and PowerManager
+ val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
+ val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
+
+ // Check if the phone is locked
+ val isPhoneLocked = keyguardManager.isKeyguardLocked
+
+ // Check if the screen is awake
+ val isScreenAwake = powerManager.isInteractive
+
+ // If the screen is off or phone is locked, wake it up
+ if (!isScreenAwake || isPhoneLocked) { wakeUpDevice() }
+
+
+// ServiceCompat.startForeground(
+// this,
+// CallNotificationBuilder.WEBRTC_NOTIFICATION,
+// Not
+// CallNotificationBuilder.getCallInProgressNotification(this, type, recipient),
+// if (Build.VERSION.SDK_INT >= 30) ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL else 0
+// )
+ }
+
+ private fun wakeUpDevice() {
+ val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
+ val wakeLock = powerManager.newWakeLock(
+ PowerManager.FULL_WAKE_LOCK or
+ PowerManager.ACQUIRE_CAUSES_WAKEUP or
+ PowerManager.ON_AFTER_RELEASE,
+ "${NonTranslatableStringConstants.APP_NAME}:WakeLock"
+ )
+
+ // Acquire the wake lock to wake up the device
+ wakeLock.acquire(3000) // Wake up for 3 seconds
+
+ // Dismiss the keyguard
+ val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
+ val keyguardLock = keyguardManager.newKeyguardLock("MyApp:KeyguardLock")
+ keyguardLock.disableKeyguard()
}
private fun registerUncaughtExceptionHandler() {
@@ -724,25 +777,57 @@ class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener {
}
}
+ // Over the course of setting up a phonecall this method is called multiple times with `types` of PRE_OFFER -> RING_INCOMING -> ICE_MESSAGE
private fun setCallInProgressNotification(type: Int, recipient: Recipient?) {
- try {
- ServiceCompat.startForeground(
- this,
- CallNotificationBuilder.WEBRTC_NOTIFICATION,
- CallNotificationBuilder.getCallInProgressNotification(this, type, recipient),
- if (Build.VERSION.SDK_INT >= 30) ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL else 0
- )
- } catch (e: IllegalStateException) {
- Log.e(TAG, "Failed to setCallInProgressNotification as a foreground service for type: ${type}, trying to update instead", e)
+
+ val typeString = when (type) {
+ TYPE_INCOMING_RINGING -> "TYPE_INCOMING_RINGING"
+ TYPE_OUTGOING_RINGING -> "TYPE_OUTGOING_RINGING"
+ TYPE_ESTABLISHED -> "TYPE_ESTABLISHED"
+ TYPE_INCOMING_CONNECTING -> "TYPE_INCOMING_CONNECTING"
+ TYPE_INCOMING_PRE_OFFER -> "TYPE_INCOMING_PRE_OFFER"
+ WEBRTC_NOTIFICATION -> "WEBRTC_NOTIFICATION"
+ else -> "We have no idea!"
+ }
+ Log.w("ACL", "Hit setCallInProgressNotification with type: $typeString")
+
+ // If notifications are enabled we'll try and start a foreground service to show the notification
+ var failedToStartForegroundService = false
+ if (CallNotificationBuilder.areNotificationsEnabled(this)) {
+ Log.w("ACL", "Notifications are ENABLED! About to try to call startForeground")
+ try {
+ ServiceCompat.startForeground(
+ this,
+ CallNotificationBuilder.WEBRTC_NOTIFICATION,
+ CallNotificationBuilder.getCallInProgressNotification(this, type, recipient),
+ if (Build.VERSION.SDK_INT >= 30) ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL else 0
+ )
+ Log.w("ACL", "Successfully called startForeground - about to bail.")
+ return
+ } catch (e: IllegalStateException) {
+ Log.e(TAG, "Failed to setCallInProgressNotification as a foreground service for type: ${type}, trying to update instead", e)
+ failedToStartForegroundService = true
+ }
+ } else {
+ Log.w("ACL", "Notifications are NOT enabled! Skipped attempt at startForeground and going straight to fullscreen intent attempt!")
}
- if (!CallNotificationBuilder.areNotificationsEnabled(this) && type == TYPE_INCOMING_PRE_OFFER) {
+
+
+
+ if (type == TYPE_INCOMING_PRE_OFFER && failedToStartForegroundService) {
+
+ Log.w("ACL", "About to create foregroundIntent and try to start the WebRtcCallActivity with type TYPE_INCOMING_PRE_OFFER")
+
// Start an intent for the fullscreen call activity
val foregroundIntent = Intent(this, WebRtcCallActivity::class.java)
.setFlags(FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_BROUGHT_TO_FRONT or Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
.setAction(WebRtcCallActivity.ACTION_FULL_SCREEN_INTENT)
startActivity(foregroundIntent)
+ return
}
+
+ Log.w("ACL", "type wasn't TYPE_INCOMING_PRE_OFFER - doing nothing =/")
}
private fun getOptionalRemoteRecipient(intent: Intent): Recipient? =
diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallMessageProcessor.kt
index c99c063d8c..88e147a720 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallMessageProcessor.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallMessageProcessor.kt
@@ -1,9 +1,15 @@
package org.thoughtcrime.securesms.webrtc
import android.Manifest
+import android.annotation.SuppressLint
+import android.app.NotificationChannel
import android.app.NotificationManager
+import android.app.PendingIntent
import android.content.Context
import android.content.Intent
+import android.os.Build
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.coroutineScope
@@ -25,18 +31,37 @@ import org.session.libsignal.protos.SignalServiceProtos.CallMessage.Type.OFFER
import org.session.libsignal.protos.SignalServiceProtos.CallMessage.Type.PRE_OFFER
import org.session.libsignal.protos.SignalServiceProtos.CallMessage.Type.PROVISIONAL_ANSWER
import org.session.libsignal.utilities.Log
+import org.thoughtcrime.securesms.calls.WebRtcCallActivity
import org.thoughtcrime.securesms.permissions.Permissions
import org.thoughtcrime.securesms.service.WebRtcCallService
-import org.thoughtcrime.securesms.util.CallNotificationBuilder
import org.webrtc.IceCandidate
+import network.loki.messenger.R
+
class CallMessageProcessor(private val context: Context, private val textSecurePreferences: TextSecurePreferences, lifecycle: Lifecycle, private val storage: StorageProtocol) {
+
+
companion object {
private const val VERY_EXPIRED_TIME = 15 * 60 * 1000L
- fun safeStartService(context: Context, intent: Intent) {
+
+
+ // TODO: While fine if the app is in the foreground, you cannot do this in modern Android if the
+ // device is locked (i.e., if you get a call when the device is locked & attempt start the
+ // foreground service) it will throw an error like:
+ // Unable to start CallMessage intent: startForegroundService() not allowed due to mAllowStartForeground false:
+ // service network.loki.messenger/org.thoughtcrime.securesms.service.WebRtcCallService
+ fun safeStartForegroundService(context: Context, intent: Intent) {
+ Log.w("ACL", "Hit safeStartForegroundService for intent action: " + intent.action)
+
+ // TODO: This is super-ugly - we're forcing a full-screen intent to wake the device up so we can
+ // TODO: successfully call `startForegroundService` in the second catch block below. This works
+ // TODO: even if the device is locked and Session has been closed down - but it's UUUUGLY. Need
+ // TODO: to find a better way.
+ showIncomingCallNotification(context)
+
// If the foreground service crashes then it's possible for one of these intents to
// be started in the background (in which case 'startService' will throw a
// 'BackgroundServiceStartNotAllowedException' exception) so catch that case and try
@@ -49,7 +74,41 @@ class CallMessageProcessor(private val context: Context, private val textSecureP
}
}
}
- }
+
+ fun createNotificationChannel(context: Context) {
+ val channel = NotificationChannel(
+ "WakeUpChannelID", // CHANNEL_ID,
+ "WakeUpChannelName", //CHANNEL_NAME,
+ NotificationManager.IMPORTANCE_HIGH
+ ).apply {
+ description = "Notifications for incoming calls"
+ }
+ val notificationManager = context.getSystemService(NotificationManager::class.java)
+ notificationManager?.createNotificationChannel(channel)
+ }
+
+ @SuppressLint("MissingPermission")
+ fun showIncomingCallNotification(context: Context) {
+ createNotificationChannel(context)
+
+ val notificationIntent = Intent(context, WebRtcCallActivity::class.java)
+ val pendingIntent = PendingIntent.getActivity(
+ context,
+ 0,
+ notificationIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ )
+
+ val notificationBuilder = NotificationCompat.Builder(context, "WakeUpChannelID")
+ .setContentTitle("Incoming Call")
+ .setContentText("Tap to answer")
+ .setSmallIcon(R.drawable.ic_baseline_call_24)
+ .setPriority(NotificationCompat.PRIORITY_MAX) // Used for devices below API 26
+ .setCategory(NotificationCompat.CATEGORY_CALL)
+ .setFullScreenIntent(pendingIntent, true)
+
+ NotificationManagerCompat.from(context).notify(999, notificationBuilder.build())
+ } }
init {
lifecycle.coroutineScope.launch(IO) {
@@ -101,7 +160,7 @@ class CallMessageProcessor(private val context: Context, private val textSecureP
private fun incomingHangup(callMessage: CallMessage) {
val callId = callMessage.callId ?: return
val hangupIntent = WebRtcCallService.remoteHangupIntent(context, callId)
- safeStartService(context, hangupIntent)
+ safeStartForegroundService(context, hangupIntent)
}
private fun incomingAnswer(callMessage: CallMessage) {
@@ -115,7 +174,7 @@ class CallMessageProcessor(private val context: Context, private val textSecureP
callId = callId
)
- safeStartService(context, answerIntent)
+ safeStartForegroundService(context, answerIntent)
}
private fun handleIceCandidates(callMessage: CallMessage) {
@@ -131,7 +190,7 @@ class CallMessageProcessor(private val context: Context, private val textSecureP
callId = callId,
address = Address.fromSerialized(sender)
)
- safeStartService(context, iceIntent)
+ safeStartForegroundService(context, iceIntent)
}
private fun incomingPreOffer(callMessage: CallMessage) {
@@ -144,7 +203,7 @@ class CallMessageProcessor(private val context: Context, private val textSecureP
callId = callId,
callTime = callMessage.sentTimestamp!!
)
- safeStartService(context, incomingIntent)
+ safeStartForegroundService(context, incomingIntent)
}
private fun incomingCall(callMessage: CallMessage) {
@@ -158,7 +217,7 @@ class CallMessageProcessor(private val context: Context, private val textSecureP
callId = callId,
callTime = callMessage.sentTimestamp!!
)
- safeStartService(context, incomingIntent)
+ safeStartForegroundService(context, incomingIntent)
}
private fun CallMessage.iceCandidates(): List {