From 4d23f11f6e56ee632d470db8d5799bb4dfab67af Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Tue, 3 Sep 2024 15:22:44 -0300 Subject: [PATCH] Add shared calling intent system. --- .../securesms/WebRtcCallActivity.java | 74 ++++------ .../app/internal/InternalSettingsFragment.kt | 8 + .../app/internal/InternalSettingsState.kt | 3 +- .../app/internal/InternalSettingsViewModel.kt | 8 +- .../components/webrtc/v2/CallActivity.kt | 17 ++- .../components/webrtc/v2/CallIntent.kt | 138 ++++++++++++++++++ .../components/webrtc/v2/CallViewModel.kt | 36 +++++ .../securesms/keyvalue/InternalValues.java | 9 ++ .../service/webrtc/AndroidCallConnection.kt | 9 +- .../service/webrtc/SignalCallManager.java | 11 +- .../securesms/util/CommunicationActions.java | 29 ++-- .../webrtc/CallNotificationBuilder.java | 25 ++-- 12 files changed, 277 insertions(+), 90 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallIntent.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/WebRtcCallActivity.java b/app/src/main/java/org/thoughtcrime/securesms/WebRtcCallActivity.java index 032103ef5c..02ca10a4c8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/WebRtcCallActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/WebRtcCallActivity.java @@ -84,9 +84,10 @@ import org.thoughtcrime.securesms.components.webrtc.controls.ControlsAndInfoCont import org.thoughtcrime.securesms.components.webrtc.controls.ControlsAndInfoViewModel; import org.thoughtcrime.securesms.components.webrtc.participantslist.CallParticipantsListDialog; import org.thoughtcrime.securesms.components.webrtc.requests.CallLinkIncomingRequestSheet; -import org.thoughtcrime.securesms.components.webrtc.v2.CallEvent; -import org.thoughtcrime.securesms.components.webrtc.v2.CallPermissionsDialogController; import org.thoughtcrime.securesms.components.webrtc.v2.CallControlsChange; +import org.thoughtcrime.securesms.components.webrtc.v2.CallEvent; +import org.thoughtcrime.securesms.components.webrtc.v2.CallIntent; +import org.thoughtcrime.securesms.components.webrtc.v2.CallPermissionsDialogController; import org.thoughtcrime.securesms.conversation.ui.error.SafetyNumberChangeDialog; import org.thoughtcrime.securesms.dependencies.AppDependencies; import org.thoughtcrime.securesms.events.WebRtcViewModel; @@ -132,23 +133,6 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan private static final int STANDARD_DELAY_FINISH = 1000; private static final int VIBRATE_DURATION = 50; - /** - * ANSWER the call via voice-only. - */ - public static final String ANSWER_ACTION = WebRtcCallActivity.class.getCanonicalName() + ".ANSWER_ACTION"; - - /** - * ANSWER the call via video. - */ - public static final String ANSWER_VIDEO_ACTION = WebRtcCallActivity.class.getCanonicalName() + ".ANSWER_VIDEO_ACTION"; - public static final String DENY_ACTION = WebRtcCallActivity.class.getCanonicalName() + ".DENY_ACTION"; - public static final String END_CALL_ACTION = WebRtcCallActivity.class.getCanonicalName() + ".END_CALL_ACTION"; - - public static final String EXTRA_ENABLE_VIDEO_IF_AVAILABLE = WebRtcCallActivity.class.getCanonicalName() + ".ENABLE_VIDEO_IF_AVAILABLE"; - public static final String EXTRA_STARTED_FROM_FULLSCREEN = WebRtcCallActivity.class.getCanonicalName() + ".STARTED_FROM_FULLSCREEN"; - public static final String EXTRA_STARTED_FROM_CALL_LINK = WebRtcCallActivity.class.getCanonicalName() + ".STARTED_FROM_CALL_LINK"; - public static final String EXTRA_LAUNCH_IN_PIP = WebRtcCallActivity.class.getCanonicalName() + ".STARTED_FROM_CALL_LINK"; - private CallParticipantsListUpdatePopupWindow participantUpdateWindow; private CallStateUpdatePopupWindow callStateUpdatePopupWindow; private CallOverflowPopupWindow callOverflowPopupWindow; @@ -184,7 +168,8 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan @SuppressLint({ "MissingInflatedId" }) @Override public void onCreate(Bundle savedInstanceState) { - Log.i(TAG, "onCreate(" + getIntent().getBooleanExtra(EXTRA_STARTED_FROM_FULLSCREEN, false) + ")"); + CallIntent callIntent = getCallIntent(); + Log.i(TAG, "onCreate(" + callIntent.isStartedFromFullScreen() + ")"); lifecycleDisposable = new LifecycleDisposable(); lifecycleDisposable.bindTo(this); @@ -214,18 +199,18 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan lifecycleDisposable.add(controlsAndInfo); - logIntent(getIntent()); + logIntent(callIntent); - if (ANSWER_VIDEO_ACTION.equals(getIntent().getAction())) { + if (callIntent.getAction() == CallIntent.Action.ANSWER_VIDEO) { enableVideoIfAvailable = true; - } else if (ANSWER_ACTION.equals(getIntent().getAction()) || getIntent().getBooleanExtra(EXTRA_STARTED_FROM_FULLSCREEN, false)) { + } else if (callIntent.getAction() == CallIntent.Action.ANSWER_AUDIO || callIntent.isStartedFromFullScreen()) { enableVideoIfAvailable = false; } else { - enableVideoIfAvailable = getIntent().getBooleanExtra(EXTRA_ENABLE_VIDEO_IF_AVAILABLE, false); - getIntent().removeExtra(EXTRA_ENABLE_VIDEO_IF_AVAILABLE); + enableVideoIfAvailable = callIntent.shouldEnableVideoIfAvailable(); + callIntent.setShouldEnableVideoIfAvailable(false); } - processIntent(getIntent()); + processIntent(callIntent); registerSystemPipChangeListeners(); @@ -302,10 +287,11 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan @Override public void onNewIntent(Intent intent) { - Log.i(TAG, "onNewIntent(" + intent.getBooleanExtra(EXTRA_STARTED_FROM_FULLSCREEN, false) + ")"); + CallIntent callIntent = getCallIntent(); + Log.i(TAG, "onNewIntent(" + callIntent.isStartedFromFullScreen() + ")"); super.onNewIntent(intent); - logIntent(intent); - processIntent(intent); + logIntent(callIntent); + processIntent(callIntent); } @Override @@ -373,6 +359,10 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan } } + private @NonNull CallIntent getCallIntent() { + return new CallIntent(getIntent()); + } + private boolean enterPipModeIfPossible() { if (isSystemPipEnabledAndAvailable()) { if (viewModel.canEnterPipMode()) { @@ -396,26 +386,20 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan return isSystemPipEnabledAndAvailable() && isInPictureInPictureMode(); } - private void logIntent(@NonNull Intent intent) { - Log.d(TAG, "Intent: Action: " + intent.getAction()); - Log.d(TAG, "Intent: EXTRA_STARTED_FROM_FULLSCREEN: " + intent.getBooleanExtra(EXTRA_STARTED_FROM_FULLSCREEN, false)); - Log.d(TAG, "Intent: EXTRA_ENABLE_VIDEO_IF_AVAILABLE: " + intent.getBooleanExtra(EXTRA_ENABLE_VIDEO_IF_AVAILABLE, false)); - Log.d(TAG, "Intent: EXTRA_LAUNCH_IN_PIP: " + intent.getBooleanExtra(EXTRA_LAUNCH_IN_PIP, false)); + private void logIntent(@NonNull CallIntent intent) { + Log.d(TAG, intent.toString()); } - private void processIntent(@NonNull Intent intent) { - if (ANSWER_ACTION.equals(intent.getAction())) { - handleAnswerWithAudio(); - } else if (ANSWER_VIDEO_ACTION.equals(intent.getAction())) { - handleAnswerWithVideo(); - } else if (DENY_ACTION.equals(intent.getAction())) { - handleDenyCall(); - } else if (END_CALL_ACTION.equals(intent.getAction())) { - handleEndCall(); + private void processIntent(@NonNull CallIntent intent) { + switch (intent.getAction()) { + case ANSWER_AUDIO -> handleAnswerWithAudio(); + case ANSWER_VIDEO -> handleAnswerWithVideo(); + case DENY -> handleDenyCall(); + case END_CALL -> handleEndCall(); } if (System.currentTimeMillis() - lastProcessedIntentTimestamp > TimeUnit.SECONDS.toMillis(1)) { - enterPipOnResume = intent.getBooleanExtra(EXTRA_LAUNCH_IN_PIP, false); + enterPipOnResume = intent.shouldLaunchInPip(); } lastProcessedIntentTimestamp = System.currentTimeMillis(); @@ -529,7 +513,7 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan lifecycleDisposable.add(viewModel.getInCallstatus().subscribe(this::handleInCallStatus)); - boolean isStartedFromCallLink = getIntent().getBooleanExtra(WebRtcCallActivity.EXTRA_STARTED_FROM_CALL_LINK, false); + boolean isStartedFromCallLink = getCallIntent().isStartedFromCallLink(); LiveDataUtil.combineLatest(LiveDataReactiveStreams.fromPublisher(viewModel.getCallParticipantsState().toFlowable(BackpressureStrategy.LATEST)), orientationAndLandscapeEnabled, viewModel.getEphemeralState(), diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsFragment.kt index c6d2bdd9fe..d92bec2a34 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsFragment.kt @@ -506,6 +506,14 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter sectionHeaderPref(DSLSettingsText.from("Calling options")) + switchPref( + title = DSLSettingsText.from("Use new calling UI"), + isChecked = state.newCallingUi, + onClick = { + viewModel.setUseNewCallingUi(!state.newCallingUi) + } + ) + radioListPref( title = DSLSettingsText.from("Audio processing method"), listItems = CallManager.AudioProcessingMethod.values().map { it.name }.toTypedArray(), diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsState.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsState.kt index 9feb9bb0b9..58b7a20c7f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsState.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsState.kt @@ -24,5 +24,6 @@ data class InternalSettingsState( val pnpInitialized: Boolean, val useConversationItemV2ForMedia: Boolean, val hasPendingOneTimeDonation: Boolean, - val hevcEncoding: Boolean + val hevcEncoding: Boolean, + val newCallingUi: Boolean ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsViewModel.kt index c626392cde..517bc83a03 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsViewModel.kt @@ -165,7 +165,8 @@ class InternalSettingsViewModel(private val repository: InternalSettingsReposito pnpInitialized = SignalStore.misc.hasPniInitializedDevices, useConversationItemV2ForMedia = SignalStore.internal.useConversationItemV2Media(), hasPendingOneTimeDonation = SignalStore.inAppPayments.getPendingOneTimeDonation() != null, - hevcEncoding = SignalStore.internal.hevcEncoding + hevcEncoding = SignalStore.internal.hevcEncoding, + newCallingUi = SignalStore.internal.newCallingUi ) fun onClearOnboardingState() { @@ -176,6 +177,11 @@ class InternalSettingsViewModel(private val repository: InternalSettingsReposito StoryOnboardingDownloadJob.enqueueIfNeeded() } + fun setUseNewCallingUi(newCallingUi: Boolean) { + SignalStore.internal.newCallingUi = newCallingUi + refresh() + } + class Factory(private val repository: InternalSettingsRepository) : ViewModelProvider.Factory { override fun create(modelClass: Class): T { return requireNotNull(modelClass.cast(InternalSettingsViewModel(repository))) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallActivity.kt index 8308e24dfc..00b953afe1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallActivity.kt @@ -7,6 +7,7 @@ package org.thoughtcrime.securesms.components.webrtc.v2 import android.annotation.SuppressLint import android.content.Context +import android.content.Intent import android.content.pm.PackageManager import android.os.Build import android.os.Bundle @@ -91,6 +92,7 @@ class CallActivity : BaseActivity(), CallControlsCallback { val callInfoCallbacks = CallInfoCallbacks(this, controlsAndInfoViewModel, compositeDisposable) observeCallEvents() + viewModel.processCallIntent(CallIntent(intent)) setContent { val lifecycleOwner = LocalLifecycleOwner.current @@ -179,6 +181,13 @@ class CallActivity : BaseActivity(), CallControlsCallback { } } + override fun onNewIntent(intent: Intent?) { + super.onNewIntent(intent) + if (intent != null) { + viewModel.processCallIntent(CallIntent(intent)) + } + } + override fun onResume() { Log.i(TAG, "onResume") super.onResume() @@ -203,13 +212,9 @@ class CallActivity : BaseActivity(), CallControlsCallback { } } - /* - TODO - if (enterPipOnResume) { - enterPipOnResume = false; - enterPipModeIfPossible(); + if (viewModel.consumeEnterPipOnResume()) { + // TODO enterPipModeIfPossible() } - */ } override fun onPause() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallIntent.kt b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallIntent.kt new file mode 100644 index 0000000000..d79d1fc67c --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallIntent.kt @@ -0,0 +1,138 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.thoughtcrime.securesms.components.webrtc.v2 + +import android.app.Activity +import android.content.Context +import android.content.Intent +import org.thoughtcrime.securesms.WebRtcCallActivity +import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.util.RemoteConfig + +/** + * CallIntent wraps an intent inside one of the call activities to allow for easy typed access to the necessary data within it. + */ +class CallIntent( + private val intent: Intent +) { + + companion object { + + private const val CALL_INTENT_PREFIX = "CallIntent" + + private fun getActivityClass(): Class = if (RemoteConfig.newCallUi || SignalStore.internal.newCallingUi) { + CallActivity::class.java + } else { + WebRtcCallActivity::class.java + } + + private fun getActionString(action: Action): String { + return "$CALL_INTENT_PREFIX.${action.code}" + } + + private fun getExtraString(extra: Extra): String { + return "$CALL_INTENT_PREFIX.${extra.code}" + } + } + + val action: Action by lazy { Action.fromIntent(intent) } + + @get:JvmName("shouldEnableVideoIfAvailable") + var shouldEnableVideoIfAvailable: Boolean + get() = intent.getBooleanExtra(getExtraString(Extra.ENABLE_VIDEO_IF_AVAILABLE), false) + set(value) { + intent.putExtra(getExtraString(Extra.ENABLE_VIDEO_IF_AVAILABLE), value) + } + + val isStartedFromFullScreen: Boolean by lazy { intent.getBooleanExtra(getExtraString(Extra.STARTED_FROM_FULLSCREEN), false) } + + val isStartedFromCallLink: Boolean by lazy { intent.getBooleanExtra(getExtraString(Extra.STARTED_FROM_CALL_LINK), false) } + + @get:JvmName("shouldLaunchInPip") + val shouldLaunchInPip: Boolean by lazy { intent.getBooleanExtra(getExtraString(Extra.LAUNCH_IN_PIP), false) } + + override fun toString(): String { + return """ + CallIntent + Action - $action + Enable video if available? $shouldEnableVideoIfAvailable + Started from full screen? $isStartedFromFullScreen + Started from call link? $isStartedFromCallLink + Launch in pip? $shouldLaunchInPip + """.trimIndent() + } + + enum class Action(val code: String) { + VIEW(Intent.ACTION_VIEW), + ANSWER_AUDIO("ANSWER_ACTION"), + ANSWER_VIDEO("ANSWER_VIDEO_ACTION"), + DENY("DENY_ACTION"), + END_CALL("END_CALL_ACTION"); + + companion object { + fun fromIntent(intent: Intent): Action { + return intent.action?.let { a -> entries.firstOrNull { a == it.code || a == getActionString(it) } } ?: VIEW + } + } + } + + private enum class Extra(val code: String) { + ENABLE_VIDEO_IF_AVAILABLE("ENABLE_VIDEO_IF_AVAILABLE"), + STARTED_FROM_FULLSCREEN("STARTED_FROM_FULLSCREEN"), + STARTED_FROM_CALL_LINK("STARTED_FROM_CALL_LINK"), + LAUNCH_IN_PIP("LAUNCH_IN_PIP") + } + + /** + * Builds an intent to launch the call screen. + */ + class Builder(val context: Context) { + private val intent = Intent(context, getActivityClass()) + + init { + withAction(Action.VIEW) + } + + fun withAddedIntentFlags(flags: Int): Builder { + intent.addFlags(flags) + return this + } + + fun withIntentFlags(flags: Int): Builder { + intent.flags = flags + return this + } + + fun withAction(action: Action?): Builder { + intent.action = action?.let { getActionString(action) } + return this + } + + fun withEnableVideoIfAvailable(enableVideoIfAvailable: Boolean): Builder { + intent.putExtra(getExtraString(Extra.ENABLE_VIDEO_IF_AVAILABLE), enableVideoIfAvailable) + return this + } + + fun withStartedFromFullScreen(startedFromFullScreen: Boolean): Builder { + intent.putExtra(getExtraString(Extra.STARTED_FROM_FULLSCREEN), startedFromFullScreen) + return this + } + + fun withStartedFromCallLink(startedFromCallLink: Boolean): Builder { + intent.putExtra(getExtraString(Extra.STARTED_FROM_CALL_LINK), startedFromCallLink) + return this + } + + fun withLaunchInPip(launchInPip: Boolean): Builder { + intent.putExtra(getExtraString(Extra.LAUNCH_IN_PIP), launchInPip) + return this + } + + fun build(): Intent { + return intent + } + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallViewModel.kt index 3368f1c99e..3f2784f941 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/v2/CallViewModel.kt @@ -32,6 +32,7 @@ import org.thoughtcrime.securesms.sms.MessageSender import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager import org.whispersystems.signalservice.api.messages.calls.HangupMessage import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds /** * Presentation logic and state holder for information that was generally done @@ -48,10 +49,18 @@ class CallViewModel( private var previousEvent: WebRtcViewModel? = null private var enableVideoIfAvailable = false + private var lastProcessedIntentTimestamp = 0L + private var enterPipOnResume = false private val internalCallScreenState = MutableStateFlow(CallScreenState()) val callScreenState: StateFlow = internalCallScreenState + fun consumeEnterPipOnResume(): Boolean { + val enter = enterPipOnResume + enterPipOnResume = false + return enter + } + fun unregisterEventBus() { EventBus.getDefault().unregister(this) } @@ -337,4 +346,31 @@ class CallViewModel( AppDependencies.signalCallManager.selectAudioDevice(SignalAudioManager.ChosenAudioDeviceIdentifier(managerDevice)) } } + + fun processCallIntent(callIntent: CallIntent) { + if (callIntent.action == CallIntent.Action.ANSWER_VIDEO) { + enableVideoIfAvailable = true + } else if (callIntent.action == CallIntent.Action.ANSWER_AUDIO || callIntent.isStartedFromFullScreen) { + enableVideoIfAvailable = false + } else { + enableVideoIfAvailable = callIntent.shouldEnableVideoIfAvailable + callIntent.shouldEnableVideoIfAvailable = false + } + + when (callIntent.action) { + CallIntent.Action.ANSWER_AUDIO -> startCall(false) + CallIntent.Action.ANSWER_VIDEO -> startCall(true) + CallIntent.Action.DENY -> deny() + CallIntent.Action.END_CALL -> hangup() + CallIntent.Action.VIEW -> Unit + } + + // Prevents some issues around intent re-use when dealing with picture-in-picture. + val now = System.currentTimeMillis() + if (now - lastProcessedIntentTimestamp > 1.seconds.inWholeMilliseconds) { + enterPipOnResume = callIntent.shouldLaunchInPip + } + + lastProcessedIntentTimestamp = now + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/InternalValues.java b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/InternalValues.java index 0861d45e9f..8c4cf87ec3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/InternalValues.java +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/InternalValues.java @@ -33,6 +33,7 @@ public final class InternalValues extends SignalStoreValues { public static final String FORCE_ENTER_RESTORE_V2_FLOW = "internal.force_enter_restore_v2_flow"; public static final String WEB_SOCKET_SHADOWING_STATS = "internal.web_socket_shadowing_stats"; public static final String ENCODE_HEVC = "internal.hevc_encoding"; + public static final String NEW_CALL_UI = "internal.new.call.ui"; InternalValues(KeyValueStore store) { super(store); @@ -192,6 +193,14 @@ public final class InternalValues extends SignalStoreValues { return getBoolean(ENCODE_HEVC, false); } + public void setNewCallingUi(boolean enabled) { + putBoolean(NEW_CALL_UI, enabled); + } + + public boolean getNewCallingUi() { + return getBoolean(NEW_CALL_UI, false); + } + public void setLastScrollPosition(int position) { putInteger(LAST_SCROLL_POSITION, position); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/AndroidCallConnection.kt b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/AndroidCallConnection.kt index af44fa6594..c47194add7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/AndroidCallConnection.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/AndroidCallConnection.kt @@ -6,7 +6,7 @@ import android.telecom.CallAudioState import android.telecom.Connection import androidx.annotation.RequiresApi import org.signal.core.util.logging.Log -import org.thoughtcrime.securesms.WebRtcCallActivity +import org.thoughtcrime.securesms.components.webrtc.v2.CallIntent import org.thoughtcrime.securesms.dependencies.AppDependencies import org.thoughtcrime.securesms.permissions.Permissions import org.thoughtcrime.securesms.recipients.RecipientId @@ -66,9 +66,10 @@ class AndroidCallConnection( if (Permissions.hasAll(context, android.Manifest.permission.RECORD_AUDIO)) { AppDependencies.signalCallManager.acceptCall(false) } else { - val intent = Intent(context, WebRtcCallActivity::class.java) - intent.action = if (isVideoCall) WebRtcCallActivity.ANSWER_VIDEO_ACTION else WebRtcCallActivity.ANSWER_ACTION - intent.flags = intent.flags or Intent.FLAG_ACTIVITY_NEW_TASK + val intent = CallIntent.Builder(context) + .withAddedIntentFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .withAction(if (isVideoCall) CallIntent.Action.ANSWER_VIDEO else CallIntent.Action.ANSWER_AUDIO) + .build() context.startActivity(intent) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java index cf8fb658c0..6cd7e1067e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java @@ -36,6 +36,7 @@ import org.signal.ringrtc.PeekInfo; import org.signal.ringrtc.Remote; import org.signal.storageservice.protos.groups.GroupExternalCredential; import org.thoughtcrime.securesms.WebRtcCallActivity; +import org.thoughtcrime.securesms.components.webrtc.v2.CallIntent; import org.thoughtcrime.securesms.crypto.SealedSenderAccessUtil; import org.thoughtcrime.securesms.database.CallLinkTable; import org.thoughtcrime.securesms.database.CallTable; @@ -1253,10 +1254,12 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall. WebRtcViewModel.State callState = s.getCallInfoState().getCallState(); if (callState.getInOngoingCall()) { - Intent intent = new Intent(context, WebRtcCallActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.putExtra(WebRtcCallActivity.EXTRA_LAUNCH_IN_PIP, true); - context.startActivity(intent); + context.startActivity( + new CallIntent.Builder(context) + .withIntentFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .withLaunchInPip(true) + .build() + ); } return s; diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java b/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java index df86473a63..f33446e0b2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java @@ -32,6 +32,7 @@ import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.WebRtcCallActivity; import org.thoughtcrime.securesms.calls.links.CallLinks; import org.thoughtcrime.securesms.components.webrtc.v2.CallActivity; +import org.thoughtcrime.securesms.components.webrtc.v2.CallIntent; import org.thoughtcrime.securesms.contacts.sync.ContactDiscovery; import org.thoughtcrime.securesms.conversation.ConversationIntents; import org.thoughtcrime.securesms.database.CallLinkTable; @@ -397,11 +398,11 @@ public class CommunicationActions { MessageSender.onMessageSent(); - Intent activityIntent = new Intent(callContext.getContext(), getCallActivityClass()); - - activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - callContext.startActivity(activityIntent); + callContext.startActivity( + new CallIntent.Builder(callContext.getContext()) + .withIntentFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .build() + ); }) .execute(); } @@ -409,13 +410,13 @@ public class CommunicationActions { private static void startVideoCallInternal(@NonNull CallContext callContext, @NonNull Recipient recipient, boolean fromCallLink) { AppDependencies.getSignalCallManager().startPreJoinCall(recipient); - Intent activityIntent = new Intent(callContext.getContext(), getCallActivityClass()); - - activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - .putExtra(WebRtcCallActivity.EXTRA_ENABLE_VIDEO_IF_AVAILABLE, true) - .putExtra(WebRtcCallActivity.EXTRA_STARTED_FROM_CALL_LINK, fromCallLink); - - callContext.startActivity(activityIntent); + callContext.startActivity( + new CallIntent.Builder(callContext.getContext()) + .withIntentFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .withEnableVideoIfAvailable(true) + .withStartedFromCallLink(fromCallLink) + .build() + ); } private static void handleE164Link(Activity activity, String e164) { @@ -479,10 +480,6 @@ public class CommunicationActions { }); } - private static Class getCallActivityClass() { - return RemoteConfig.newCallUi() ? CallActivity.class : WebRtcCallActivity.class; - } - private interface CallContext { @NonNull Permissions.PermissionsBuilder getPermissionsBuilder(); void startActivity(@NonNull Intent intent); diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallNotificationBuilder.java b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallNotificationBuilder.java index 9e3e64e0ef..efa2bade61 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallNotificationBuilder.java +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallNotificationBuilder.java @@ -15,10 +15,9 @@ import androidx.core.app.Person; import org.signal.core.util.PendingIntentFlags; import org.thoughtcrime.securesms.MainActivity; import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.WebRtcCallActivity; +import org.thoughtcrime.securesms.components.webrtc.v2.CallIntent; import org.thoughtcrime.securesms.notifications.NotificationChannels; import org.thoughtcrime.securesms.recipients.Recipient; -import org.thoughtcrime.securesms.service.webrtc.ActiveCallManager; import org.thoughtcrime.securesms.service.webrtc.WebRtcCallService; import org.thoughtcrime.securesms.util.ConversationUtil; @@ -49,13 +48,13 @@ public class CallNotificationBuilder { private enum LaunchCallScreenIntentState { CONTENT(null, 0), - AUDIO(WebRtcCallActivity.ANSWER_ACTION, 1), - VIDEO(WebRtcCallActivity.ANSWER_VIDEO_ACTION, 2); + AUDIO(CallIntent.Action.ANSWER_AUDIO, 1), + VIDEO(CallIntent.Action.ANSWER_VIDEO, 2); - final @Nullable String action; - final int requestCode; + final @Nullable CallIntent.Action action; + final int requestCode; - LaunchCallScreenIntentState(@Nullable String action, int requestCode) { + LaunchCallScreenIntentState(@Nullable CallIntent.Action action, int requestCode) { this.action = action; this.requestCode = requestCode; } @@ -219,17 +218,17 @@ public class CallNotificationBuilder { } private static PendingIntent getActivityPendingIntent(@NonNull Context context, @NonNull LaunchCallScreenIntentState launchCallScreenIntentState) { - Intent intent = new Intent(context, WebRtcCallActivity.class); - intent.setAction(launchCallScreenIntentState.action); + CallIntent.Builder builder = new CallIntent.Builder(context); + builder.withAction(launchCallScreenIntentState.action); if (launchCallScreenIntentState == LaunchCallScreenIntentState.CONTENT) { - intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); + builder.withIntentFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); } - intent.putExtra(WebRtcCallActivity.EXTRA_STARTED_FROM_FULLSCREEN, launchCallScreenIntentState == LaunchCallScreenIntentState.CONTENT); - intent.putExtra(WebRtcCallActivity.EXTRA_ENABLE_VIDEO_IF_AVAILABLE, false); + builder.withStartedFromFullScreen(launchCallScreenIntentState == LaunchCallScreenIntentState.CONTENT); + builder.withEnableVideoIfAvailable(false); - return PendingIntent.getActivity(context, launchCallScreenIntentState.requestCode, intent, PendingIntentFlags.updateCurrent()); + return PendingIntent.getActivity(context, launchCallScreenIntentState.requestCode, builder.build(), PendingIntentFlags.updateCurrent()); } private static boolean deviceVersionSupportsIncomingCallStyle() {