diff --git a/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java b/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java index c714aa0eea..10e63101d6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java @@ -406,7 +406,6 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im @SuppressWarnings("CodeBlock2Expr") @SuppressLint("InlinedApi") private void saveToDisk() { - Log.w("ACL", "Asked to save to disk!"); MediaItem mediaItem = getCurrentMediaItem(); if (mediaItem == null) return; diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java index 802c7d2374..0db028fc63 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java @@ -146,11 +146,8 @@ public abstract class MessageRecord extends DisplayRecord { } else if (isOutgoingCall()) { callType = CallMessageType.CALL_OUTGOING; } else if (isMissedCall()) { - Log.w("ACL", "We think CALL_MISSSED"); - callType = CallMessageType.CALL_MISSED; } else { - Log.w("ACL", "We think CALL_FIRST_MISSSED"); callType = CallMessageType.CALL_FIRST_MISSED; } return new SpannableString(UpdateMessageBuilder.INSTANCE.buildCallMessage(context, callType, getIndividualRecipient().getAddress().serialize())); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/KeyCachingService.java b/app/src/main/java/org/thoughtcrime/securesms/service/KeyCachingService.java index 9c1d771af6..dc22bf5e83 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/KeyCachingService.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/KeyCachingService.java @@ -235,7 +235,6 @@ public class KeyCachingService extends Service { private void foregroundService() { if (TextSecurePreferences.isPasswordDisabled(this) && !TextSecurePreferences.isScreenLockEnabled(this)) { - Log.w("ACL", "Stopping foreground service in KeyCachingService"); stopForeground(true); return; } 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 64f13437e9..befc0aa5ec 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt @@ -1,6 +1,5 @@ package org.thoughtcrime.securesms.service -import android.app.ForegroundServiceStartNotAllowedException import android.app.KeyguardManager import android.content.BroadcastReceiver import android.content.Context @@ -22,6 +21,12 @@ import androidx.lifecycle.LifecycleService import androidx.lifecycle.lifecycleScope import androidx.localbroadcastmanager.content.LocalBroadcastManager import dagger.hilt.android.AndroidEntryPoint +import java.util.UUID +import java.util.concurrent.ExecutionException +import java.util.concurrent.Executors +import java.util.concurrent.ScheduledFuture +import java.util.concurrent.TimeUnit +import javax.inject.Inject import org.session.libsession.messaging.calls.CallMessageType import org.session.libsession.utilities.Address import org.session.libsession.utilities.FutureTaskListener @@ -49,6 +54,7 @@ import org.thoughtcrime.securesms.webrtc.UncaughtExceptionHandlerManager import org.thoughtcrime.securesms.webrtc.WiredHeadsetStateReceiver import org.thoughtcrime.securesms.webrtc.audio.OutgoingRinger import org.thoughtcrime.securesms.webrtc.data.Event +import org.thoughtcrime.securesms.webrtc.data.State as CallState import org.thoughtcrime.securesms.webrtc.locks.LockManager import org.webrtc.DataChannel import org.webrtc.IceCandidate @@ -59,13 +65,6 @@ import org.webrtc.PeerConnection.IceConnectionState.DISCONNECTED import org.webrtc.PeerConnection.IceConnectionState.FAILED import org.webrtc.RtpReceiver import org.webrtc.SessionDescription -import java.util.UUID -import java.util.concurrent.ExecutionException -import java.util.concurrent.Executors -import java.util.concurrent.ScheduledFuture -import java.util.concurrent.TimeUnit -import javax.inject.Inject -import org.thoughtcrime.securesms.webrtc.data.State as CallState @AndroidEntryPoint class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener { @@ -333,32 +332,8 @@ 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 -// ) - - - - // 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 registerUncaughtExceptionHandler() { uncaughtExceptionHandlerManager = UncaughtExceptionHandlerManager().apply { registerHandler(ProximityLockRelease(lockManager)) @@ -660,6 +635,20 @@ class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener { } } + /** + * Handles remote ICE candidates received from a signaling server. + * + * This function is called when a new ICE candidate is received for a specific call. + * It extracts the candidate information from the intent, creates IceCandidate objects, + * and passes them to the CallManager to be added to the PeerConnection. + * + * @param intent The intent containing the remote ICE candidate information. + * The intent should contain the following extras: + * - EXTRA_CALL_ID: The ID of the call. + * - EXTRA_ICE_SDP_MID: An array of SDP media stream identification strings. + * - EXTRA_ICE_SDP_LINE_INDEX: An array of SDP media line indexes. + * - EXTRA_ICE_SDP: An array of SDP candidate strings. + */ private fun handleRemoteIceCandidate(intent: Intent) { val callId = getCallId(intent) val sdpMids = intent.getStringArrayExtra(EXTRA_ICE_SDP_MID) ?: return @@ -754,7 +743,6 @@ class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener { } private fun wakeUpDeviceIfLocked() { - // Get the KeyguardManager and PowerManager val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager @@ -766,9 +754,6 @@ class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener { val isScreenAwake = powerManager.isInteractive if (!isScreenAwake) { - - Log.w("ACL", "Screen is NOT awake - waking it up!") - val wakeLock = powerManager.newWakeLock( PowerManager.FULL_WAKE_LOCK or PowerManager.ACQUIRE_CAUSES_WAKEUP or @@ -777,70 +762,47 @@ class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener { ) // Acquire the wake lock to wake up the device - wakeLock.acquire(3000) // Wake up for 3 seconds + wakeLock.acquire(3000) - val startTime = System.currentTimeMillis() - while (!powerManager.isInteractive) { /* Busy wait until we're awake */ } - val endTime = System.currentTimeMillis() - val duration = endTime - startTime - Log.w("ACL", "Woken up in $duration ms") - } else { - Log.w("ACL", "Screen is awake - doing nothing") + while (!powerManager.isInteractive) { + /* Busy wait until we're awake - typically takes less than ~10ms */ + } } + // Dismiss the keyguard val keyguardLock = keyguardManager.newKeyguardLock("MyApp:KeyguardLock") keyguardLock.disableKeyguard() } - // Over the course of setting up a phonecall this method is called multiple times with `types` of PRE_OFFER -> RING_INCOMING -> ICE_MESSAGE + // Over the course of setting up a phone call this method is called multiple times with `types` + // of PRE_OFFER -> RING_INCOMING -> ICE_MESSAGE private fun setCallInProgressNotification(type: Int, recipient: Recipient?) { wakeUpDeviceIfLocked() - - 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", "NOOOOOOOOOOTIFICATION - 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, + 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!") + // Notifications are NOT enabled! Skipped attempt at startForeground and going straight to fullscreen intent attempt! } - - - if ((type == TYPE_INCOMING_PRE_OFFER || type == TYPE_INCOMING_RINGING) && failedToStartForegroundService) { - //if (failedToStartForegroundService) { - Log.w("ACL", "DID SOMETHING - foregroundIntent to WebRtcCallActivity for TYPE_INCOMING_PRE_OFFER") wakeUpDeviceIfLocked() - - // 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) @@ -848,8 +810,6 @@ class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener { 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 280acbcac2..4e8a74bbfc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallMessageProcessor.kt @@ -51,31 +51,24 @@ class CallMessageProcessor(private val context: Context, private val textSecureP - // TODO: While fine if the app is in the foreground, you cannot do this in modern Android if the + // 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) - - - - // 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 - // to re-start the service in the foreground + // Attempt to start the call service.. try { context.startService(intent) } catch(e: Exception) { + // ..however due to tightened restrictions in Android 12 and above this will not + // work (BackgroundServiceStartNotAllowedException) if the device is asleep / locked + // so we have to wake the device first and then try to start it as a foreground service. + // Note: Attempting to start a foreground service while the device is asleep / locked + // will also cause an exception. + wakeUpDeviceIfLocked(context) try { ContextCompat.startForegroundService(context, intent) } catch (e2: Exception) { Log.e("Loki", "Unable to start CallMessage intent: ${e2.message}") - - // 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) } } } @@ -92,23 +85,11 @@ class CallMessageProcessor(private val context: Context, private val textSecureP notificationManager?.createNotificationChannel(channel) } + // Wake the device up if it's asleep / locked - used when we receive an incoming call private fun wakeUpDeviceIfLocked(context: Context) { - - // Get the KeyguardManager and PowerManager - val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager val powerManager = context.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 (!isScreenAwake) { - - Log.w("ACL", "CMP: Screen is NOT awake - waking it up!") - - val wakeLock = powerManager.newWakeLock( PowerManager.FULL_WAKE_LOCK or PowerManager.ACQUIRE_CAUSES_WAKEUP or @@ -116,41 +97,9 @@ class CallMessageProcessor(private val context: Context, private val textSecureP "${NonTranslatableStringConstants.APP_NAME}:WakeLock" ) - // Acquire the wake lock to wake up the device - wakeLock.acquire(3000) // Wake up for 3 seconds - } else { - Log.w("ACL", "CMP: Screen is awake - doing nothing") + // We only need the wake lock briefly + wakeLock.acquire(3000) } - // Dismiss the keyguard - //val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager - //val keyguardLock = keyguardManager.newKeyguardLock("MyApp:KeyguardLock") - //keyguardLock.disableKeyguard() - } - - @SuppressLint("MissingPermission") - fun showIncomingCallNotification(context: Context) { - - wakeUpDeviceIfLocked(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()) } } @@ -164,8 +113,7 @@ class CallMessageProcessor(private val context: Context, private val textSecureP Log.i("Loki", "Contact is approved?: $approvedContact") if (!approvedContact && storage.getUserPublicKey() != sender) continue - // if the user has not enabled voice/video calls - // or if the user has not granted audio/microphone permissions + // If the user has not enabled voice/video calls or if the user has not granted audio/microphone permissions if ( !textSecurePreferences.isCallNotificationsEnabled() || !Permissions.hasAll(context, Manifest.permission.RECORD_AUDIO)